Reputation: 1376
I'm using this code to load my view into a DialogFragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
SyncPopup syncPopup = new SyncPopup(getActivity(), this,_callback);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setSoftInputMode(STYLE_NO_INPUT);
getDialog().setCanceledOnTouchOutside(false);
return syncPopup;
}
this code is in my custom DialogFragment. So this
points to DialogFragment.
SyncPopup holds all my view logic. I'm using this pattern so that I can reuse SyncPopup elsewhere.
Inside my SyncPopup I'm running a AsyncTask and in onPostExecute
I want to close the DialogFragment.
->
_parentFragment
was injected via constructor see code above (used this
pointer).
SyncInfo si = new SyncInfo(email, Start, End);
new AsyncTask<SyncInfo, Void, String>() {
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
_callback.onSyncFinish();
_parentFragment.dismiss();
}
@Override
protected String doInBackground(SyncInfo... params) {
SyncInfo si = params[0];
return Cache.sync(si.Email, si.Start, si.End);
}
}.execute(si);
I've tested this code but in Google Analytics I see that _parentFragment.dismiss();
causes -> IllegalStateException (@SyncPopup$8:onPostExecute:221) {main}
I guess it has nothing to do with the AsyncTask since I also get this problem with other DialogFragments where I use the same pattern.
Am I doing anything wrong?
I already read that you shouldn't close DialogFragment with -> getDialog().dismiss()
but this isn'T the case. I close it by calling dismiss on the reference I passed into my custom view.
UPDATE:
Can't say why but now the exception ocurred on my android 4.03 device while I tried to debug something other. So I can provide the stack trace:
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x40c131f8)
FATAL EXCEPTION: main
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1343)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1354)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.dismissInternal(DialogFragment.java:189)
at android.support.v4.app.DialogFragment.dismiss(DialogFragment.java:155)
at com.mxp.time.popups.SyncPopup$8.onPostExecute(SyncPopup.java:239)
at com.mxp.time.popups.SyncPopup$8.onPostExecute(SyncPopup.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:602)
at android.os.AsyncTask.access$600(AsyncTask.java:156)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:615)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4493)
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:788)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:555)
at dalvik.system.NativeStart.main(Native Method)
Sending signal. PID: 24095 SIG: 9
GC_CONCURRENT freed 1081K, 21% free 13393K/16747K, paused 4ms+3ms
Starting setup.
right now I'm trying this:
@Override
public void onSaveInstanceState(Bundle outState) {
//first saving my state, so the bundle wont be empty.
//http://code.google.com/p/android/issues/detail?id=19917
outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
super.onSaveInstanceState(outState);
}
Cheers, Stefan
Upvotes: 1
Views: 4164
Reputation: 15817
You can't perform a fragment transaction when the activity that fragment belongs to is on the background. Since your dialog is really a fragment, dismissing it triggers a fragment transaction. I guess that the AsyncTask
you are using to dismiss the dialog terminates its execution by calling onPostExecute
while the activity that holds the fragment used to start it is on the background. Lo and behold, there the IllegalStateException
is thrown.
There are at least a couple of workarounds. The simplest is to just rework your UI design avoiding a dialog to show the progess of your task. It's the suggestion contained in the official documentation guide on Dialogs, in the first aside on the right, just next to the green vertical bar.
The other possible solution I know of is slightly more complex. Well, it's just a different kind of complexity: code, rather than user interface design. You need to use a Handler
to collect messages from the AsyncTask
. Instead of directly dismissing the dialog, the AsyncTask
sends a handler the message that it has finished. The handler receives the message, and processes it, dismissing the fragment. However, the handler must be capable of pausing and resuming message processing whenever the activity holding it goes on the background (e.g. in onPause
) and gets resumed from the background (e.g. in onResume
). In this way, when the activity goes on the background, and the AsyncTask
finishes triggering the dialog dismissal, the handler receives the dismissal message, but holds it until the activity is resumed and it's now safe to perform the implied fragment transaction.
Upvotes: 6