We are seeing the same error reported here and here and none of the solutions provided have worked for us.
Our setup is slightly different though:
The use case that crashes the app 100% of the time is a deeplink IF we are previously on a react native screen. After some investigation we think the following occurs:
Libraries:
We have tried one thing: IF "react-native-screens": "2.10.1" and we don't force that version, ie change other dependencies to use that version, the resulting app has react-native-screens 2.10.1 AND 2.9.0 and the issue seems to be gone. However though this doesn't sound like a very reliable thing to do.
The concerning lines are the following:
at com.swmansion.rnscreens.ScreenContainer.removeMyFragments(ScreenContainer.java:238)
at com.swmansion.rnscreens.ScreenContainer.onDetachedFromWindow(ScreenContainer.java:250)
The stack trace we have is the following
java.lang.RuntimeException: Unable to resume activity {com.company.package.flavour.debug/com.company.MainActivity}: java.lang.IllegalStateException: FragmentManager is already executing transactions
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4219)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4251)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2019)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7410)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1790)
at androidx.fragment.app.FragmentManager.execSingleAction(FragmentManager.java:1826)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303)
at com.swmansion.rnscreens.ScreenContainer.removeMyFragments(ScreenContainer.java:238)
at com.swmansion.rnscreens.ScreenContainer.onDetachedFromWindow(ScreenContainer.java:250)
at android.view.View.dispatchDetachedFromWindow(View.java:19626)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3814)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5431)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5402)
at android.view.ViewGroup.removeView(ViewGroup.java:5333)
at androidx.fragment.app.FragmentContainerView.removeView(FragmentContainerView.java:317)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1262)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1516)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2019)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1965)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861)
at androidx.fragment.app.Fragment.performResume(Fragment.java:2745)
at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:373)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1211)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2601)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:269)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:478)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:467)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:204)
at android.app.Activity.performResume(Activity.java:7964)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4209)
Looks like this line is quite crucial: androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303) and is triggered here: https://github.com/software-mansion/react-native-screens/blob/master/android/src/main/java/com/swmansion/rnscreens/ScreenContainer.java#L277. Making it synchronous (commitNowAllowingStateLoss instead of commitAllowingStateLoss) makes it reach invalid state where there is another transaction already being executed (see https://android.googlesource.com/platform/frameworks/support/+/84448d71fda0a24ba5d60fe9368ac47b97564c88/fragment/src/main/java/androidx/fragment/app/FragmentManagerImpl.java#1707 triggered by androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861) for setting the execution of transition and here: https://android.googlesource.com/platform/frameworks/support/+/84448d71fda0a24ba5d60fe9368ac47b97564c88/fragment/src/main/java/androidx/fragment/app/FragmentManagerImpl.java#1643 triggered by androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:303) for check that throws an exception from the issue). Seems like the only solution to this is to change the commitNowAllowingStateLoss to commitAllowingStateLoss in ScreenContainer, but it also may lead to other problems. Can you check if it resolves the issue and does not introduce any new issues?
@WoLewicki - I've tested the change suggested but unfortunately it also ends in the same crash.
For the time being we have disabled this from being used in android, however, the react native engineers would like to enabled it at some point.
I'm happy to try any other suggestion. I did try executePendingTransactions before the code is doing the for loop on mFragmentManager.getFragments() but ends the same.
Can you post stacktraces of the crashes in the changed flows?
Using commitAllowingStateLoss instead of commitNowAllowingStateLoss
java.lang.RuntimeException: Unable to resume activity {com.package.flavour.debug/com.package.MainActivity}: java.lang.IllegalStateException: FragmentManager is already executing transactions
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4219)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4251)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2019)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7410)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1790)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1855)
at androidx.fragment.app.FragmentManager.executePendingTransactions(FragmentManager.java:489)
at com.swmansion.rnscreens.ScreenContainer.onDetachedFromWindow(ScreenContainer.java:253)
at android.view.View.dispatchDetachedFromWindow(View.java:19626)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3814)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5431)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5402)
at android.view.ViewGroup.removeView(ViewGroup.java:5333)
at androidx.fragment.app.FragmentContainerView.removeView(FragmentContainerView.java:317)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1262)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1516)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2019)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1965)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861)
at androidx.fragment.app.Fragment.performResume(Fragment.java:2745)
at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:373)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1211)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2601)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:269)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:478)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:467)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:204)
at android.app.Activity.performResume(Activity.java:7964)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4209)
For this second stackTrace I've added transaction.commitAllowingStateLoss(); in the for loop:
`private void removeMyFragments() {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
boolean hasFragments = false;
for (Fragment fragment : mFragmentManager.getFragments()) {
if (fragment instanceof ScreenFragment && ((ScreenFragment) fragment).mScreenView.getContainer() == this) {
transaction.remove(fragment);
transaction.commitAllowingStateLoss();
hasFragments = true;
}
}
}`
And the crash seems to happen when we do mFragmentManager.executePendingTransactions(); on method onDetachedFromWindow()
java.lang.RuntimeException: Unable to resume activity {com.package.flavour.debug/com.package.MainActivity}: java.lang.IllegalStateException: FragmentManager is already executing transactions
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4219)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4251)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2019)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7410)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManager.ensureExecReady(FragmentManager.java:1790)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1855)
at androidx.fragment.app.FragmentManager.executePendingTransactions(FragmentManager.java:489)
at com.swmansion.rnscreens.ScreenContainer.onDetachedFromWindow(ScreenContainer.java:257)
at android.view.View.dispatchDetachedFromWindow(View.java:19626)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3814)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3806)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5431)
at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5402)
at android.view.ViewGroup.removeView(ViewGroup.java:5333)
at androidx.fragment.app.FragmentContainerView.removeView(FragmentContainerView.java:317)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1262)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1516)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2019)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1965)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1861)
at androidx.fragment.app.Fragment.performResume(Fragment.java:2745)
at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:373)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1211)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368)
at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637)
at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2601)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:269)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:478)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:467)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:204)
at android.app.Activity.performResume(Activity.java:7964)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4209)
Now the interesting thing is - if I do the change suggested:
if (hasFragments) {
transaction.commitAllowingStateLoss();
}
And I remove mFragmentManager.executePendingTransactions(); from method onDetachedFromWindow() all seems to work fine. My guess would be that the navigation components take care of the transactions enqueued in ScreenContainer.
Adding back commitNowAllowingStateLoss on the if above and not having executePendingTransactions() in onDetachedFromWindow() ends up in the same crash as well.
Hmm you can try and keep the configuration that causes no crashes, and see if the new issues arise from this. This implementation was for sure like this for a reason so deleting mFragmentManager.executePendingTransactions(); may produce new problems, but it would be good to check it for sure. Thank you for your feedback and please comment here the progress!
Cool - I'll get in touch with the team and see if we can try this and give the app a good shake.
I have a closed source code base I can reproduce this with consistently. The latest has not fixed it, Let me see if I can troubleshoot the issue against my code base and PR. As a work around one can not use the enableScreens on the RN side and this does not occur. We are trying to avoid that
Not using enableScreens is not a solution since it just removes all of the integration with the native navigation. There is still no reproduction passed here so there is not much we can do with it. @amutsch could you pass a simple example where this can be seen? You probably don't need anything specific to your application, rather some steps that are crucial to see this.
@WoLewicki Unfortunately the app is so large we do not have a good single source to boil it down to. I did make a minor change to ScreenContainer similar to what was outlined above. We have this in testing with our QA team and if everything continues to look good I will get a PR up.
Thank you! Please comment here also with the results.
The Application is being hit hard by the release testing teams this week and the automation teams this week. We have closed out most of the crashes related to this bug. I will update and PR later this week.
@WoLewicki The testing is continuing to go good on this PR, I'll be getting that PR setup this week.
I was able to consistently get this to happen by
-> Opening an app that invokes enableScreens()
-> Background the app
-> Open the app's settings and revoke a permission (e.g. location)
-> Try to restore the app from the app drawer.
The crash happens every single time.
I haven't forgotten about this issue, I'm monitoring our production crashes as we roll out to make sure my changes have this resolved.
@amutschBBY any first insights already? 馃檹
@LcTwisk We are investigating some additional similar issues in onUpdate, onPause calls from native. I will start getting a fork prepped to PR back but likely won't create the PR until we work through some additional fragment manager issues. So far the onResume issues seem to be working well.
Most helpful comment
I was able to consistently get this to happen by
-> Opening an app that invokes
enableScreens()-> Background the app
-> Open the app's settings and revoke a permission (e.g. location)
-> Try to restore the app from the app drawer.
The crash happens every single time.