Avoiding IllegalStateException for DialogFragments

Álvaro Blanco Cabrero
2 min readAug 17, 2018

--

Photo by Maximilian Weisbecker on Unsplash

Almost every single Android developer using DialogFragment has once faced this issue: you are waiting for a service call or some long time based task to complete in order to present the user a feedback dialog, then your app crash with the following exception:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1341)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1352)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)

I won’t enter into further explanations on why this exception occurs, this is greatly explained in this blog post:

TL;DR: Fragment transactions can not be committed after onSaveInstanceState has been called, so what to do in order to show DialogFragments inside asynchronous callbacks, without worrying about lifecycle and without resorting in commitAllowingStateLoss aka “I do not care if the DialogFragment is shown”?

Many solutions on StackOverflow had overcome this, i.e:

But would not be great to have a generic and simple solution to use across apps without forcing you to add too much boilerplate code to every component?

Let’s rely on Architecture Components to solve this problem, by simply creating a presenter class observing Activity’s lifecycle and controlling when transactions can be made or not.

Very simple: just create and instance of DialogFragmentPresenter in your Activity and delegate show method to it. No more exceptions won’t occur in we try to show the dialog on an illegal state.

But this approach do not cover DialogFragment presentation deferring, so lets update our code to allow it:

Thats it, now our DialogFragments will remain stored until onResume is called again to show them. (Note that I declared a list of pending dialogs, although the most usual case is to only present once at a time, but lets do not be so restrictive and allow the possibility of spamming the user with multiple dialogs :D )

P.S: Although documentation warns not to play with Fragment transactions in onResume() (https://developer.android.com/reference/android/support/v4/app/FragmentActivity#onResume()), it is not very clear which is the real reason of this statement and looking across the source code of FragmentActivity does not unveil it: It appears to be safe making transactions after onResume() is called, and all our tests across different use cases and different API versions had work properly.

Thanks for reading this article. Be sure to like and recommend it if you found it helpful!

For more about Android development, you can follow me or connect with me through on Github and Linkedin.

--

--