Question

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);
Was it helpful?

Solution

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.

OTHER TIPS

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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top