There are numerous posts about how to handle a configuration change during an AsyncTask, but none I have found give a clear solution regarding apps that are in background (onPause()) when an AsyncTask finishes and tries to dismiss a DialogFragment (compatibility library).
Here is the problem, if I have an AsyncTask running that should dismiss a DialogFragment in onPostExecute(), I get an IllegalStateException if the app is in the background when it tries to dismiss the DialogFragment.
private static class SomeTask extends AsyncTask<Void, Void, Boolean> {
public SomeTask(SomeActivity tActivity)
{
mActivity = tActivity;
}
private SomeActivity mActivity;
/** Set the view during/after config change */
public void setView(Activity tActivity) {
mActivity tActivity;
}
@Override
protected Boolean doInBackground(Void... tParams) {
try {
//simulate some time consuming process
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ignore) {}
return true;
}
@Override
protected void onPostExecute(Boolean tRouteFound) {
mActivity.dismissSomeDialog();
}
}
The Activity looks like this:
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
public class SomeActivity extends FragmentActivity {
public void someMethod() {
...
displaySomeDialog();
new SomeTask(this).execute();
...
}
public void displaySomeDialog() {
DialogFragment someDialog = new SomeDialogFragment();
someDialog.show(getFragmentManager(), "dialog");
}
public void dismissSomeDialog() {
SomeDialogFragment someDialog = (SomeDialogFragment) getFragmentManager().findFragmentByTag("dialog");
someDialog.dismiss();
}
....
}
Works fine UNLESS the app switches to background while SomeTask is still running. In that case, when SomeTask tries to dismissSomeDialog(), I get an IllegalStateException.
05-25 16:36:02.237: E/AndroidRuntime(965): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
All of the posts I’ve seen seem to point in some kludgy direction with elaborate workarounds. Isn’t there some android way of handling this? If it were a Dialog instead of a DialogFragment, then the Activity’s dismissDialog() would handle it correctly. If it were a real DialogFragment instead of one from the ACP, then dismissAllowingStateLoss() would handle it. Isn’t there something like this for the ACP version of DialogFragment?
To get around the illegal state exception issue and essentially implement a dismissAllowingStateLoss() can be done using the following.
This should solve the issue without the hacky code. The same can also be applied for show if you have threads communicating through a handler with the UI thread using dialog.show(); Which can cause an illegal state exception as well
@joneswah is correct, given the posters question.
If you are using the support library, replace
with
For future Googlers:
@Alex Lockwood raises good and valid concerns with this solution. The solution does solve the error and will work in most cases, but hints that there are issues with the approach in the original question, from a UX perspective.
The Activity should assume that the async task may not complete and that it will not perform onPostExecute(). Whatever UI action (ie, spinner, ideally not a dialog) is started to notify the user of the async operation, should have provisions to stop automatically either on a timeout or by tracking state and checking in onRestore/onResume type lifecycle events to ensure the UI is updated properly. Services may also be worth investigating.