I can't seem to grasp why this is happening. This code:
mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);
works just fine. However, this code:
mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);
throws the following exception:
W/WindowManager( 569): Attempted to add window with non-application token WindowToken{438bee58 token=null}. Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049): at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049): at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049): at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049): at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049): at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049): at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049): at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049): at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049): at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049): ... 11 more
Any ideas why this is happening? I'm calling this from the onCreate method.
I am using Android version 2.1 with API Level 7. I faced with this (or similar) problem and solved by using this:
Dialog dialog = new Dialog(this);
instead of this:
Dialog dialog = new Dialog(getApplicationContext());
For me worked changing
builder = new AlertDialog.Builder(getApplicationContext());
to
builder = new AlertDialog.Builder(ThisActivityClassName.this);
Weird thing is that the first one can be found in google tutorial and people get error on this..
Which API version are you using? If I'm right about what the problem is then this was fixed in Android 1.6 (API version 4).
It looks like the object reference that getApplicationContext() is returning just points to null. I think you're having a problem similar to one I had in that some of the code in the onCreate() is being run before the window is actually done being built. This is going to be a hack, but try launching a new Thread in a few hundred milliseconds (IIRC: 300-400 seemed to work for me, but you'll need to tinker) that opens your ProgressDialog and starts anything else you needed (eg. network IO). Something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
// do all your other stuff here
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mProgressDialog = ProgressDialog.show(
YouTube.this.getApplicationContext(), "",
YouTube.this.getString(R.string.loading), true);
// start time consuming background process here
}
}, 1000); // starting it in 1 second
}
I don't think this is a timing issue around a null application context
Try extending Application within your app (or just use it if you already have)
public class MyApp extends Application
Make the instance available as a private singleton. This is never null
private static MyApp appInstance;
Make a static helper in MyApp (which will use the singleton)
public static void showProgressDialog( CharSequence title, CharSequence message )
{
prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}
BOOM!!
Also, check out android engineer's answer here: WindowManager$BadTokenException
One cause of this error may be trying to display an application
window/dialog through a Context that is not an Activity.
Now, i agree, it does not make sense that the method takes a Context param, instead of Activity..
Having read the above answers i found that for my situation the following fixed the issue.
This threw the error
myButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
MyDialogue dialog = new MyDialogue(getApplicationContext());
dialog.show();
}
});
Based on the previous answers that suggested the context was the wrong one, i changed the getApplicationContext() to retrieve the context from the View passed in to the buttons onClick method.
myButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
MyDialogue dialog = new MyDialogue(v.getContext());
dialog.show();
}
});
I don't fully understand the workings of Java so i could be wrong, but I'm guessing that for my specific situation the cause could have been related to the fact that the above snippet was defined in an Abstract Activity class; inherited and used by many Activities, perhaps that contributed to the fact that getApplicationContext() doesn't return a valid context?? (Just a guess).
I am creating a map view with itemized overlays. I was creating my itemizedoverlay like this from my mapActivity:
OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);
I found that I would get the "android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application" exception when my itemizedoverlay's onTap method was triggered(when the location is tapped on the mapview).
I found that if I simply passed, 'this' instead of 'getApplicationContext()' to my constructor, the problem went away. This seems to support alienjazzcat's conclusion. weird.
For Activities shown within TabActivities use getParent()
final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());
instead of
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
For Android 2.2
Use this code:
//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);
instead of this code:
// this code produces an ERROR:
//android.view.WindowManager$BadTokenException:
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);
Remark: My custom dialog is created outside activity.onCreateDialog(int dialogId) method.
Try -
AlertDialog.Builder builder = new AlertDialog.Builder(getParent());
Had a similar problem with (compatibility) Fragments in which using a getActivity() within ProgressDialog.show() crashes it. I'd agree that it is because of timing.
A possible fix:
mContext = getApplicationContext();
if (mContext != null) {
mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}
instead of using
mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);
Place the mContext as early as possible to give it more time to grab the context. There's still no guarantee that this will work, it just reduces the likelihood of a crash. If it still doesn't work, you'd have to resort to the timer hack (which can cause other timing problems like dismissing the dialog later).
Of course, if you can use this or ActivityName.this, it's more stable because this already points to something. But in some cases, like with certain Fragment architectures, it's not an option.
(For future references)
I think it's because there's differences in Application Context and Activity Context, as explained here: http://www.doubleencore.com/2013/06/context/
Which means that we can't show dialog using Application Context. That's it.
For using dialogs inside activities, do it this way:
private Context mContext;
private AlertDialog.Builder mBuilder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
//using mContext here refering to activity context
mBuilder = new AlertDialog.Builder(mContext);
//...
//rest of the code
//...
}
For using dialogs inside fragments, do it this way:
private Context mContext;
private AlertDialog.Builder mBuilder;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
mContext = getActivity();
//using mContext here refering to fragment's hosting activity context
mBuilder = new AlertDialog.Builder(mContext);
//...
//rest of the code
//...
return mRootView;
}
That's it ^_^
What I did to get around this was to create a base class for all my activities where I store global data. In the first activity, I saved the context in a variable in my base class like so:
Base Class
public static Context myucontext;
First Activity derived from the Base Class
mycontext = this
Then I use mycontext instead of getApplicationContext when creating dialogs.
AlertDialog alertDialog = new AlertDialog.Builder(mycontext).create();
If you're calling ProgressDialog.show() in a fragment, casting the mContext to Activity worked for me.
ProgressDialog pd = new ProgressDialog((Activity) mContext);
This is a common problem.
Use this instead of getApplicationContext()
That should solve your problem
I have implemented Alert Dialog for exception throwing on to the current activitty view.Whenever I had given like this
AlertDialog.Builder builder = new AlertDialog.Builder(context);
Given same Window Exception.I write code for alert out of onCreate().So simple I used context = this; after setContentView() statement in onCreate() method.Taken context variable as global like Context context;
Code sample is
static Context context;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.network);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
context = this;
.......
Alert Method Sample is
private void alertException(String execMsg){
Log.i(TAG,"in alertException()..."+context);
Log.e(TAG,"Exception :"+execMsg);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......
It works fine for me.Actually I searched for this error on StackOverflow I found this query.After reading all responses of this post, I tried this way so It works .I thought this is a simple solution for overcome the exception.
Thanks,
Rajendar
if you have a problem on groupActivity dont use this.
PARENT is a static from the Parent ActivityGroup.
final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);
instead of
final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());
A dialog is always created and displayed as a part of an Activity. You need to pass in an Activity context instead of the Application context.
http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog
Related
In MainActivity, Context and MainActivity are different?
They are exactly getApplicationContext() and MainActivity.this in Method.
The reason I'm asking this is because i got error because of them.
if these are different, Complier didn't display red line in code.
I thought it was the same until now.
I got this error code.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.writeweight, PID: 24595
java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:843)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:806)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:693)
at androidx.appcompat.app.AppCompatDialog.setContentView(AppCompatDialog.java:95)
at androidx.appcompat.app.AlertController.installContent(AlertController.java:232)
at androidx.appcompat.app.AlertDialog.onCreate(AlertDialog.java:279)
at android.app.Dialog.dispatchOnCreate(Dialog.java:702)
at android.app.Dialog.show(Dialog.java:424)
at com.example.writeweight.MainActivity.onOptionsItemSelected(MainActivity.java:85)
at android.app.Activity.onMenuItemSelected(Activity.java:4182)
And I changed from getApplicationContext() to MainActivity.this and it worked well.
Code
MainActivity.class
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); // HERE
builder.setTitle("SET");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(),"TEST", Toast.LENGTH_SHORT).show();
}
});
AlertDialog dialog = builder.create();
dialog.show();
return true;
}
Tell me please.
Thank you
getApplicationContext() (somewhat unsurprisingly) returns the application context, whilst MainActivity.this is itself an activity context. Themes associated with your activity will differ from your application. They aren't the same thing.
if these are different, Complier didn't display red line in code.
You wont see an error, because it's only a Context that is requested. I haven't tried it, but you probably could use an Application instance so long as you specify the theme as well by using new AlertDialog.Builder(getApplicationContext(), /* theme res id */)
However, all the examples in the Android documentation use an Activity context, so I'd suggest you just go with that.
I know there are number of solutions given for this question, but none of them worked for me. Even after having all of the checks, my application crashes on dismiss dialog.
Here is the code I am using :
public void dismissDialog(int dialogId) {
Dialog dialog = getDialog(dialogId);
Activity activity = mActivity.get();
if (activity != null && !activity.isFinishing()) {
if (dialog != null) {
if (dialog.isShowing()) {
dialog.dismiss();
}
mDialogsMap.remove(dialogId);
}
}
}
I am dismissing all the dialog using this method but still users are getting these crashes.
See logs :
Fatal Exception: java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView{144f7eb V.E...... R......D 0,0-684,240} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:424)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:350)
at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:118)
at android.app.Dialog.dismissDialog(Dialog.java:362)
at android.app.Dialog.dismiss(Dialog.java:345)
at com.syntonic.freeway.android.DialogController.dismissDialog(SourceFile:64)
at com.syntonic.freeway.android.ui.OffersAndRewardDetailActivity$4.onSuccess(SourceFile:770)
at com.gs.jutil.web.NetworkCallback.onProgress(SourceFile:64)
at com.gs.jutil.web.NetworkCallback.validate(SourceFile:7)
at com.gs.jutil.web.NetworkCallback$1.run(SourceFile:46)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5451)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
It is because that the dialog is closed after the view has been destroyed... Try this
if (view.isShown()) {
dialog.dismiss()
}
Your issue is that you're trying to close a dialog that isn't attached.
java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView{144f7eb V.E...... R......D 0,0-684,240} not attached to window manager
Instead of passing around dialogId's, you should pass the dialog objects around. Are you storing a hashmap or list of dialogs that are open and trying to close them iteratively? What exactly are you trying to achieve? If you're passing the dialogs around, you can at least guarantee that they're attached, or at least check that they're still attached.
Here's an example of how I've managed clicks inside fragments
https://github.com/jmitchell38488/android-todo-app/blob/master/app/src/main/java/com/github/jmitchell38488/todo/app/ui/activity/ListActivity.java
List<DialogFragment> dialogs = new ArrayList<>();
dialogs.add(myNewDialog);
#Override
public void onDialogPositiveClick(DialogFragment dialog) {
if (some_code_that_does_not_dismiss) {
dialog.remove(dialog);
...
} else {
dialog.dismiss();
}
}
edit based on feedback:
If you're storing weak references (which I think is wrong - just how many dialogs can you have open at any time or stored in memory?), then you need to use a DialogManager to manage them, as well as a DialogFactory to instantiate them, on top of which, you need an abstract class that extends DialogFragment so that you can centralise your dismiss and management logic. That way all you need to do is:
DialogFactory.getInstance(/** args **/)
Then inside onStop or onDestroy:
// If you want to store them in the bundle
SerializedDialogManager = DialogManager.serialize();
// Else, delete them
DialogManager.shutdown();
Inside your shutdown, you check each dialog to see if it still exists and can be dismissed:
List<Integer> dialogIds = new ArrayList<>();
for (int id ; dialogIds) {
Dialog d = getDialog(id);
if (d != null && d.isShown()) {
d.dismiss();
}
}
But really, you should be handling your dismiss actions inside the dialogs.
Food for thought, but I personally think that you shouldn't bother too much with weak references and let the activities/dialogs deal with instantiation and shut down.
I'm using the excellent ACRA library to receive error reports from my apps.
I'm receiving a lot of reports from customers concerning an NPE in DialogFragment, but Im unable to reproduce it :
java.lang.NullPointerException
at android.support.v4.app.DialogFragment.onActivityCreated(SourceFile:366)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:892)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1083)
at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1065)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(SourceFile:1844)
at android.support.v4.app.FragmentActivity.onStart(SourceFile:519)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1133)
at android.app.Activity.performStart(Activity.java:4475)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1929)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
at android.app.ActivityThread.access$600(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
The NPE happens inside the support library (#line 366):
353 #Override
354 public void onActivityCreated(Bundle savedInstanceState) {
(...)
361 View view = getView();
362 if (view != null) {
363 if (view.getParent() != null) {
364 throw new IllegalStateException("DialogFragment can not be attached to a container view");
365 }
366 mDialog.setContentView(view);
367 }
Im unable to reproduce the problem on any of my device (from 2.2 to 4.1.1). Since there's no reference to any of my code, is it a library bug?
I have had to debug the same issue in a project.
Typically Dialog fragment is used as below
#Override
public Dialog onCreateDialog (Bundle savedInstanceState)
{
//Create custom dialog
return dialog;
}
Try updating it to the following
#Override
public Dialog onCreateDialog (Bundle savedInstanceState)
{
//Create custom dialog
if (dialog == null)
super.setShowsDialog (false);
return dialog;
}
This will prevent DialogFragment.onAtivityCreated() from executing methods on the null member variable mDialog.
This is a relatively common crash that I've seen reported within StackOverflow, and it's due to the dialog not being created properly, causing mDialog to be null. The brute force method I initially used to prevent the crash:
#Override
public void onActivityCreated(Bundle arg0) {
if (getDialog() == null ) { // Returns mDialog
// Tells DialogFragment to not use the fragment as a dialog, and so won't try to use mDialog
setShowsDialog( false );
}
super.onActivityCreated(arg0); // Will now complete and not crash
}
While the above is probably better than a crash, this doesn't address the root cause of why the dialog failed to be created. There could be many reasons for that and that's what needs to be debugged.
In my situation, I found that I needed to implement DialogFragment's onCreateDialog() instead of onCreateView() to properly create the dialog 100% of the time. (onCreateView() almost always works to create the dialog, but I PROVED that there are reproducible corner cases where onCreateView() fails to work, causing mDialog to become null. On the other hand, I always found that onCreateDialog() properly created DialogFragment's dialog.)
DialogFragment.mDialog can be null if DialogFragment.dismiss() is called before onActivityCreated() is called.
I had the NPE.
But surrounding the super.OnActivityCreated with a try/catch did not help.
What did help was the removal of a static field that was left over from copying an example.
So, no static fields inside an overridden DialogFragment.
No it's not. This is the common error if the SetContentView crashes. setContentView calls the constructors of the Controls of your view. One throwed a nullPointerException.
If you are overriding onCreateView(..) to instantiate the view of your DialogFragment you need to show it using a fragment transaction and put setShowsDialog to false to avoid this error. i.e:
//Instantiate your DialogFragment and fragmentManager previously and then just do this:
dialogFragment.setShowsDialog(false);
FragmentTransaction fT = fragmentManager.beginTransaction();
fT.add(0, dialogFragment, TAG);
fT.commit();
I have a problem creating a custom dialog. But I don't find the failure. Hopefully anybody can help me ...
protected Dialog onCreateDialog(int id) {
Dialog dialog = null;
switch (id) {
case DIALOG_ABOUT_ID:
dialog = buildAboutDialog();
break;
default:
dialog = null;
}
return dialog;
}
...
public Dialog buildAboutDialog() {
Context mContext = getApplicationContext();
Dialog dialog = new Dialog(mContext);
dialog.setContentView(R.layout.about_dialog);
dialog.setTitle("About this application");
return dialog;
}
Results in the following error:
12-30 19:27:02.593: ERROR/AndroidRuntime(383): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
I checked if the returned dialog == null - but it isn't.
I also tried the second way (inflater) described at http://developer.android.com/guide/topics/ui/dialogs.html#CustomDialog
I found out, that the dialog needs to be created with
Dialog dialog = new Dialog(this);
and not
Context mContext = getApplicationContext();
Dialog dialog = new Dialog(mContext);
I don't exactly know why. Perhaps anybody can explain it to me?
Dialog dialog = new Dialog(contex);
dialog.setContentView(R.layout.help_content);
this works for me .. may be getapplicationcontext not getting context of the your main class.
As it turns out, Context of an activity is different then object returned by getApplicationContext(). This you can check by using logging, just output ActivityName.this and getApplicationContext.
The object returned by getApplicationContext is a global thing while context of an activity, well, belongs to that activity only.
Log.e(tag,""+ getApplicationContext());
Log.e(tag,""+CustomDialogActivity.this);
where CustomDialogActivity is my activity in which I want to show my dialog.
Dialogs require context of an activity and getApplicationContext() does not provide that. As written here (read comments) context of an activity is superset of getApplicationContext(). so It is a good thing to always pass context of an activity rather then the global context.
Also to answer ffleandro's comment of this page if you are inside onClick() you can use
ActivityName.this to refer to activity. Hope this helps
I've an application that you can show and close several Dialogs with:
showDialog(...)
removeDialog(...)
I play a little bit with the application and when there is no any Dialog on the screen, I press the menu button and I go to the main android screen.
After a while, I enter again into my application and sometimes, I get this RuntimeException:
java.lang.IllegalArgumentException: Activity#onCreateDialog did not create a dialog for id 4
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
at android.app.ActivityThread.access$2200(ActivityThread.java:126)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4595)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: Activity#onCreateDialog did not create a dialog for id 4
at android.app.Activity.createDialog(Activity.java:878)
at android.app.Activity.restoreManagedDialogs(Activity.java:867)
at android.app.Activity.performRestoreInstanceState(Activity.java:815)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1096)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2565)
... 11 more
Any idea?
Thank you very much.
UPDATE, more information:
The current onCreateDialog implementation is:
protected Dialog onCreateDialog(int id){
Builder b = new AlertDialog.Builder(this);
if(id == 4){
b.setMessage(...);
b.setItems(items, new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
Intent i = new Intent(Current.this, Another.class);
startActivity(i);
}
});
return b.create();
}
return null;
}
In order to call this function I do:
removeDialog(4);
showDialog(4);
In API level 8, onCreateDialog(int) was deprecated in favor of onCreateDialog(int,Bundle). If you implement only the latter method and run the app on a device with an API level lower than 8, you get the described error message.
The solution is to implement onCreateDialog(int)
For SDK version < 8, if you return null in onCreateDialog you get Exception java.lang.IllegalArgumentException.
After experiencing this same issue (and finding that calling removeDialog from within onPause doesn't work reliably), I developed a workaround that seems to function (although it's admittedly a hack).
As seen in the grepcode link posted by antslava, in method performRestoreInstanceState, onRestoreInstanceState is called right before restoreManagedDialogs and is passed the same instance of Bundle savedInstanceState.
final void performRestoreInstanceState(Bundle savedInstanceState) {
onRestoreInstanceState(savedInstanceState);
restoreManagedDialogs(savedInstanceState);
}
Thus, there is opportunity to modify the Bundle savedInstanceState that is passed to restoreManagedDialogs from within the onRestoreInstanceState method.
To prevent any and all managed dialogs from being restored, one could implement onRestoreInstanceState in the following way:
// This same variable is defined as private in the Activity class. I need
// access to it, so I redefine it here.
private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
final Bundle b = savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
if (null != b) {
savedInstanceState.remove(SAVED_DIALOGS_TAG);
}
}
This causes the Bundle referenced by key "android:savedDialogs" to be removed from Bundle savedInstanceState, which subsequently causes the call to restoreManagedDialogs to immediately return when it finds that this key cannot be found:
private void restoreManagedDialogs(Bundle savedInstanceState) {
final Bundle b = savedInstanceState.getBundle(SAVED_DIALOGS_TAG);
if (b == null) {
return;
}
...
}
This will cause onCreateDialog to not be called while restoring the Activity, effectively "hiding" any dialogs, thus preventing the scenario where one must return null from onCreateDialog from occurring.
This isn't a 'one size fits all' solution, but given my requirements it seems to fit the bill. By reviewing the code in grepcode for several platform versions (1.6, 2.1, 2.2, 2.2.2, and 4.0.3), it appears that this solution should work consistently given these existing implementations.
Have you implemented OnCreateDialog as presented here? When you call showDialog(4) for the first time, OnCreateDialog(4) will be called and you need to create the dialog and return it from this method.
Are you properly returning the dialog in onCreateDialog? If you were to do dialog.show() in dialog create but return some other dialog you could perhaps get a result like that.
Or are you doing any sort of manipulation in of the dialog object in onPrepareDialog