Search code examples
androidandroid-fragmentsandroid-dialogfragmentillegalstateexception

DialogFragment IllegalStateException when screen goes off


First of all, I've read dozens of SO questions and read excellent post by Alex Lockwood about the IllegalStateException problems connected with fragment transactions: https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html - tl;dr I've done my homework

But what I didn't find anywhere is the IllegalStateException problem when the screen goes off and we are trying to commit fragment transaction - show DialogFragment in my case.

What is exactly happening in my app is reacting to other activity result and later on showing a DialogFragment. As suggested by many SO users, I'm not showing dialog from onActivityResult but from onPostResume (I've tried also with onResumeFragments) Simplified code looks like this

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    Timber.i("${this::class.java.simpleName} onActivityResult")
    activityResult = ActivityResult(this::class, requestCode, resultCode, data)
}

override fun onPostResume() {
    super.onPostResume()
    Timber.i("${this::class.java.simpleName} onPostResume")
    activityResult?.let { ActivityResultRepository.resultsSubject.onNext(it) }
}

override fun onResumeFragments() {
    super.onResumeFragments()
    Timber.i("${this::class.java.simpleName} onResumeFragments")
}

I couldn't reproduce exception on my device (Mate 20 pro) or on emulator but I'm receiving crash reports from users of my app (0.5% users affected)

My assumption is, my app is trying to show a dialog after screen goes off. Screen going off is an arbitrary event that causes onSaveInstanceState method to be called and it can be called right before my onPostResume method. However this is only my assumption!, maybe there is another cause of the exception

Has anyone experienced similar problems and manage to handle them? I know I can use commitAllowingStateLoss but firstly - show method of DialogFragment doesn't allow to do that, would have to show dialog manually by using FragmentManager (don't know if there are any implications), secondly commitAllowingStateLoss is generally a bad thing to do

I'm adding crash report although everyone saw it already somewhere :)

Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
       at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2053)
       at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2079)
       at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:678)
       at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:632)
       at android.support.v4.app.DialogFragment.show(DialogFragment.java:143)

Solution

  • This happens a lot. Activity is not in the correct state to show a dialog. You can guard yourself with this:

    if (!isFinishing() && !isDestroyed()) {
        dialog.show();
    }