I am using the showDialog()
and dismissDialog()
to show progress dialogs in my app. Moved from creating the dialog and calling show()
Please be aware that every time you change the orientation, a new instance of your Activity
(and consequently of your Dialog
via onCreateDialog
) is created. You can verify this by adding a log statement in either constructor.
Although difficult to say without having a glance at your code, I'm guessing you're calling dismissDialog
on an older instance of your Activity
.
Consider the following Activity
that simply shows an empty Dialog
when a button is clicked and starts a TimerTask
to dismiss it after 10 seconds:
public class Test extends Activity {
private Dialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
Button btn = (Button) findViewById(R.id.testButton);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
new Timer().schedule(new TimerTask() {
@Override public void run() { dialog.dismiss(); }
}, 10000);
Test.this.showDialog(1);
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
if(id == 1) {
if(dialog == null) { dialog = new Dialog(this); }
return dialog;
}
return super.onCreateDialog(id);
}
}
This code has a problem similar to the one you're describing: If - during the 10 seconds - the orientation is changed, the Dialog
is never dismissed. Why? Because at the time the TimerTask
is run
, a whole different set of Test
and Dialog
instances has been created (during orientation change) and the TimerTask
's dialog
instance variable references a Test
instance that is different from the one that is currently active on the screen.
Obviously there are several ways to deal with this issue (mostly depending on your application), one quick (dirty?) way to fix the above code would be to simply make the dialog
field static
:
private static Dialog dialog;
After searching through all kinds of forums, i just did the following:
I call the showDialog(MyDialogID) AND dismissDialog(MyDialogId) out of the handleMessage(myMessage) Method from my Handler.
Before that i called showDialog in my onCreate()-Method and tried to dismiss the dialog in handle-Message. Why this solved the problem, i cant tell.
After pressing the home button and navigating to app morelocal (change device language), when I came back to my app, new dialog boxes could not be closed via dismissDialog (I launched the dialog from activity onCreate).
The solution was to call removeDialog instead of dissmissDialog(). This has been recommended by Harri above, many thx.
I have created an Android bug report:
13858
Solution is to create your dialog using OnPostCreate instead of OnCreate. I added that info to the bug report and recommended to improve the dialog documentation.
I recently ran into this problem as well. I have an application with many activities all needing to access global objects (db connections, lists of data, etc) and so I overrode the Application class. To that end, I realized all I needed was a reference to the latest instance of the progress dialog in my runnable that I was using to dismiss the dialog. This is what I came up with and it gracefully survives phone reorientations:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
mHandler = new Handler();
mApplication = (MyApplication)getApplication();
mFileStorage = (CheckBoxPreference)getPreferenceScreen().findPreference("fileStorage");
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle("Location Update");
mProgressDialog.setMessage("Moving databases to new storage location.");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.setCanceledOnTouchOutside(false);
mApplication.setProgressDialog(mProgressDialog);
}
@Override
protected void onResume() {
super.onResume();
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
mPreferences.registerOnSharedPreferenceChangeListener(this);
if (sUpdateThread != null && sUpdateThread.isAlive()) {
mProgressDialog.show();
}
}
@Override
protected void onPause() {
super.onPause();
mPreferences.unregisterOnSharedPreferenceChangeListener(this);
if (sUpdateThread != null && sUpdateThread.isAlive()) {
mProgressDialog.hide();
mApplication.setProgressDialog(null);
}
}
....random stuff here....
private Runnable showProgressRunnable = new Runnable() {
public void run() {
mProgressDialog.show();
}
};
private Runnable hideProgressRunnable = new Runnable() {
public void run() {
if (mApplication.getProgressDialog() != null) {
mApplication.getProgressDialog().dismiss();
}
}
};
My thread does an mHandler.post(showProgressRunnable) when the task starts and then does an mHandler.post(hideProgressRunnable) when the task finishes. Since the reference to the latest ProgressDialog is now stored in the Application class, I can close it out reliably since I am no longer holding on to an old object reference.
Link for posterity: http://developer.android.com/reference/android/app/Application.html
I wasted over a day on a problem like this with dialogs not being dismissed when calling dismissDialog. It occurred after my first screen rotation and never worked afterwards. I had been using an external AsyncTask which was passed a referenced to the state explicitly.
In the end the solution was really simple.... removeDialog(int)
instead of dismissDialog(int)
.
I had spent what felt like forever proving to myself I was doing the dismiss on the correct activity and checking the number of times things were called etc, but it was caused by some of the jiggerypokery behind the scenes.
The best solution for me seems to use removeDialog(id) instead of dismissDialog(); Less re-usage this way, but safer (doesn't throw anything) and no problems when changing orientation.