ncapdevi / FragNav

An Android library for managing multiple stacks of fragments
1.5k stars 220 forks source link

IllegalStateException: FragmentManager is already executing transactions #170

Closed alashow closed 5 years ago

alashow commented 6 years ago

How can I avoid this exception?

Fatal Exception: java.lang.IllegalStateException: FragmentManager is already executing transactions
    androidx.fragment.app.FragmentManagerImpl.ensureExecReady (SourceFile:2207)
    androidx.fragment.app.FragmentManagerImpl.execPendingActions (SourceFile:2267)
    androidx.fragment.app.FragmentManagerImpl.executePendingTransactions (SourceFile:814)
    com.ncapdevi.fragnav.FragNavController.tryPopFragmentsFromCurrentStack (SourceFile:745)
    my.app.ui.base.BaseFragNavActivity.navigate (SourceFile:76)
    my.app.ui.base.interfaces.FragmentNavigator$DefaultImpls.navigate$default (SourceFile:10)
    my.app.ui.main.module.Fragment$initLive$7.invoke (SourceFile:80)
    my.app.ui.main.module.Fragment$initLive$7.invoke (SourceFile:24)
    my.app.ui.utils.extensions.LiveDataExtensionsKt$witness$1.onChanged (SourceFile:16)
    my.app.util.arch.SingleLiveEvent$observe$1.onChanged (SourceFile:26)
    androidx.lifecycle.LiveData.considerNotify (SourceFile:113)
    androidx.lifecycle.LiveData.dispatchingValue (SourceFile:126)
    androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged (SourceFile:424)
    androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged (SourceFile:376)
    androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent (SourceFile:355)
    androidx.lifecycle.LifecycleRegistry.forwardPass (SourceFile:293)
    androidx.lifecycle.LifecycleRegistry.sync (SourceFile:333)
    androidx.lifecycle.LifecycleRegistry.moveToState (SourceFile:138)
    androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent (SourceFile:124)
    androidx.fragment.app.Fragment.performStart (SourceFile:2487)
    androidx.fragment.app.FragmentManagerImpl.moveToState (SourceFile:1494)
    androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState (SourceFile:1784)
    androidx.fragment.app.BackStackRecord.executeOps (SourceFile:797)
    androidx.fragment.app.FragmentManagerImpl.executeOps (SourceFile:2625)
    androidx.fragment.app.FragmentManagerImpl.executeOpsTogether (SourceFile:2411)
    androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute (SourceFile:2366)
    androidx.fragment.app.FragmentManagerImpl.execPendingActions (SourceFile:2273)
    androidx.fragment.app.FragmentManagerImpl$1.run (SourceFile:733)
    android.os.Handler.handleCallback (Handler.java:789)
    android.os.Handler.dispatchMessage (Handler.java:98)
    android.os.Looper.loop (Looper.java:164)
    android.app.ActivityThread.main (ActivityThread.java:6938)
    java.lang.reflect.Method.invoke (Method.java)
    com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
    com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)

76's line is navController.executePendingTransactions():

 override fun navigate(fragment: Fragment, pop: Int) {
        when (fragment) {
            is BaseFragment<*> -> setTitle(fragment.getTitle(resources))
        }
        when (pop == 0) {
            true -> navController.pushFragment(fragment)
            else -> {
                if (!navController.isRootFragment) {
                    navController.popFragments(pop)
                } else Timber.e("Tried to pop when it's root fragment. Not cool.")

                navController.pushFragment(fragment)
            }
        }
        navController.executePendingTransactions()
    }
alashow commented 5 years ago

Am I the only getting this crash? There have been 7 instances reported by Crashlytics

mateherber commented 5 years ago

You should use 3.0 then you will not have to call the executePendingTransactions.

mateherber commented 5 years ago

Or as a quick and nasty workaround put a try-catch around it

alashow commented 5 years ago

Does 3.0 version uses androidx now?

alashow commented 5 years ago

Looks like it's not. I had some building issues with Android Jetifier last time, let me try again though.

mateherber commented 5 years ago

There's a PR for that: https://github.com/ncapdevi/FragNav/pull/178

alashow commented 5 years ago

I just tried 3.0, and the build passed okay.

Do we just remove navController.executePendingTransactions() now?

BTW, it will be a nice addition to upgrade to androidx now. Even without build issues, it's less job to do for Android Jetifier

mateherber commented 5 years ago

Yeah hopefully that will do it. If you experience anything weird please report back.

alashow commented 5 years ago

Will do! Closing for now.

alashow commented 5 years ago

Apparently, It wasn't fixed yet. Still same error. Using v3.0.0 and not calling executePendingTransactions anywhere.

       at androidx.fragment.app.FragmentManagerImpl.checkStateLoss(SourceFile:2080)
       at androidx.fragment.app.FragmentManagerImpl.enqueueAction(SourceFile:2106)
       at androidx.fragment.app.BackStackRecord.commitInternal(SourceFile:683)
       at androidx.fragment.app.BackStackRecord.commit(SourceFile:637)
       at com.ncapdevi.fragnav.FragNavController.addPreviousFragment(SourceFile:677)
       at com.ncapdevi.fragnav.FragNavController.createTransactionWithOptions(SourceFile:364)
       at com.ncapdevi.fragnav.FragNavController.addPreviousFragment(SourceFile:32)
       at com.ncapdevi.fragnav.FragNavController$DefaultFragNavPopController.tryPopFragments(SourceFile:875)
       at com.ncapdevi.fragnav.tabhistory.CurrentTabHistoryController.popFragments(SourceFile:13)
       at com.ncapdevi.fragnav.FragNavController.getRootFragment(SourceFile:329)
       at com.ncapdevi.fragnav.FragNavController.addPreviousFragment(SourceFile:375)
       at app.base.BaseFragNavActivity.navigate(SourceFile:70)
       at app.main.payment.web.PaymentWebFragment$onDone$1.invoke(SourceFile:30)
       at app.main.payment.web.PaymentWebFragment$onDone$1.invoke(SourceFile:25)
       at app.main.payment.web.PaymentWebViewClient.isCallbackUrl(SourceFile:62)
       at app.main.payment.web.PaymentWebViewClient.shouldOverrideUrlLoading(SourceFile:34)
       at apM.a(SourceFile:1)
       at xq.b(SourceFile:81)
       at org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading(SourceFile:172)
       at android.os.MessageQueue.nativePollOnce(MessageQueue.java)
       at android.os.MessageQueue.next(MessageQueue.java:328)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:6269)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
mateherber commented 5 years ago

This is not the same stack trace

mateherber commented 5 years ago

The problem here is that you're trying to commit a fragment when the activity's state is not ready for it (already started to finish or inside configuration change). You either make sure that in the callback you make sure that navigation happens only inside the activity's active lifecycle or set TransactionOptions allowStateLoss to true

Article on this matter: https://medium.com/inloopx/demystifying-androids-commitallowingstateloss-cb9011a544cc

alashow commented 5 years ago

Thanks! Will report back once I try fixing it.

ncapdevi commented 5 years ago

@alashow Will assume it's fixed since we didn't hear back. Comment again if there's an issue and I can reopen this.