react-native-screens: Android crashes nondeterministically when restoring from background
Hi,
at least in release builds I’m getting crashes when restoring app from background, but not always. I replaced ReactActivity
with ReactFragmentActivity
.
react-native: 0.57.0
Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com._redacted_.app/com._redacted_.app.MainActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.swmansion.rnscreens.Screen$ScreenFragment: calling Fragment constructor caused an exception
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2747)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2808)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1541)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
at android.support.v4.app.Fragment.instantiate(Fragment.java:386)
at android.support.v4.app.FragmentContainer.instantiate(FragmentContainer.java:33)
at android.support.v4.app.FragmentState.instantiate(FragmentState.java:79)
at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:3080)
at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:152)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:330)
at com.facebook.react.ReactFragmentActivity.onCreate(ReactFragmentActivity.java:54)
at com._redacted_.app.MainActivity.onCreate(MainActivity.java:19)
at android.app.Activity.performCreate(Activity.java:6852)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2700)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2808)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1541)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
Caused by java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Constructor.java)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.support.v4.app.Fragment.instantiate(Fragment.java:364)
at android.support.v4.app.FragmentContainer.instantiate(FragmentContainer.java:33)
at android.support.v4.app.FragmentState.instantiate(FragmentState.java:79)
at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:3080)
at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:152)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:330)
at com.facebook.react.ReactFragmentActivity.onCreate(ReactFragmentActivity.java:54)
at com._redacted_.app.MainActivity.onCreate(MainActivity.java:19)
at android.app.Activity.performCreate(Activity.java:6852)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2700)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2808)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1541)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
Caused by java.lang.IllegalStateException: Screen fragments should never be restored
at com.swmansion.rnscreens.Screen$ScreenFragment.<init>(Screen.java:19)
at java.lang.reflect.Constructor.newInstance0(Constructor.java)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at android.support.v4.app.Fragment.instantiate(Fragment.java:364)
at android.support.v4.app.FragmentContainer.instantiate(FragmentContainer.java:33)
at android.support.v4.app.FragmentState.instantiate(FragmentState.java:79)
at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:3080)
at android.support.v4.app.FragmentController.restoreAllState(FragmentController.java:152)
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:330)
at com.facebook.react.ReactFragmentActivity.onCreate(ReactFragmentActivity.java:54)
at com._redacted_.app.MainActivity.onCreate(MainActivity.java:19)
at android.app.Activity.performCreate(Activity.java:6852)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2700)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2808)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1541)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6365)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
Fatal Exception: 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 com.swmansion.rnscreens.ScreenContainer.tryCommitTransaction(ScreenContainer.java:99)
at com.swmansion.rnscreens.ScreenContainer.updateIfNeeded(ScreenContainer.java:173)
at com.swmansion.rnscreens.ScreenContainer.access$000(ScreenContainer.java:21)
at com.swmansion.rnscreens.ScreenContainer$1.doFrame(ScreenContainer.java:34)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:134)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:105)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:964)
at android.view.Choreographer.doCallbacks(Choreographer.java:778)
at android.view.Choreographer.doFrame(Choreographer.java:710)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:172)
at android.app.ActivityThread.main(ActivityThread.java:6590)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 12
- Comments: 72 (28 by maintainers)
Links to this issue
Commits related to this issue
- android: Workaround for github.com/kmagiera/react-native-screens/issues/17 — committed to keybase/client by jzila 5 years ago
- android: Workaround for github.com/kmagiera/react-native-screens/issues/17 — committed to keybase/client by jzila 5 years ago
- android: Workaround for github.com/kmagiera/react-native-screens/issues/17 (#17070) — committed to keybase/client by jzila 5 years ago
- android: Workaround for github.com/kmagiera/react-native-screens/issues/17 (#17070) — committed to keybase/client by jzila 5 years ago
- Avoid android crashes on restoring from background Might prevent the 'Unable to start activity ComponentInfo' errors. via https://github.com/software-mansion/react-native-screens/issues/17 — committed to knyar/svitle-radio-mobile by knyar 4 years ago
- docs(android, install): note MainActivity::onCreate may need an override to avoid crashes Related discussion: https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-700650097 — committed to mikehardy/react-native-screens by mikehardy 4 years ago
- [templates] Fix bare templates on Android to avoid potential inconsistencies when restoring from background (#12043) Fixes #12002. Unless a developer makes a conscious effort to carefully restore app... — committed to expo/expo by kevgrig 3 years ago
- [templates] Fix bare templates on Android to avoid potential inconsistencies when restoring from background (#12043) Fixes #12002. Unless a developer makes a conscious effort to carefully restore app... — committed to expo/expo by kevgrig 3 years ago
- Workaround for github.com/software-mansion/react-native-screens/issues/17 (#17070) — committed to zdam-egzamin-zawodowy/mobile-app by Kichiyaki 3 years ago
- [native] Fix react-native-screens crash Summary: I got [this crash](https://gist.github.com/Ashoat/0790c412e2619d7c7173bae8032c64f5) when starting the Android app. In bcd544f01005030cfa232046845ab1e... — committed to CommE2E/comm by Ashoat 3 years ago
As a workaround for this issue I suggest adding the following code to the main activity class (the one that extends
ReactFragmentActivity
:I was having this issue with RN 0.60.5 and react-native-screens 1.0.0-alpha22. Easily reproducible when developer option
Don't keep activities
is on.Fixed the issue as @kmagiera suggested, by applying the following diff:
The fix should be OK for now, but apparently it’s not a good long term solution. Is there any more proper way to solve for this?
@WoLewicki Has there been a fix or support added for restoring screen fragments? What are the repro steps? I’m on react-native 0.63.3 and react-native-screens 3.4.0, and we are starting to see this crash in our app in production. We haven’t added the first recommended fix of passing null into onCreate since we want to preserve state if the app is relaunched from the background - but I also haven’t been able to repro this locally. Any help here would be appreciated to better understand what’s going on and what’s the current state of things.
Question: Instead of forcibly passing
null
to the constructor, what is the downside of selectively removing the fragment info fromsavedInstanceState
?Not really sure about the correct keys to use (for portability) though. I found those
android:support:fragments
andandroid:fragments
when logging the bundle content.This does not result in a crash with both Keep Activities on or off.
same issue on react-natvie-screens 2.15.1 everything works correctly but on 3.7.0 - app started to crash
Why is this not mentioned in the readme?
@kmagiera here you say https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067 to change the way we call super.onCreate. I can confirm that calling onCreate with null fixes the problem. I see that the example app also calls onCreate with null. So is this the fix for that?
If we switch
super.onCreate(null)
tosuper.onCreate(savedInstanceState);
and then put the app in background and go to the android settings -> display -> font size -> change the font size and navigate to back to the app -> you will be able to reproduce the issue.Note: App needs to be build in release mode for it to crash.
+1
The workaround doesn’t solve it for me - anyone found something else which could cause this?
We should perhaps make it a default behavior for the main activity class in RN core as restoring instance state won’t work in RN this way anyways
😱
as comment suggested pass null to onCreate, however, on foldable phone the whole application will restart whenever we split into multi-window. Any other ways could prevent such issue? Thanks.
I think the consensus was that it is an intractable design problem because the javascript view state is not well known on Activity restore when there’s a configuration change or similar, so there is nothing better / more correct to do other than assume things might be out of sync and rebuild your view from the application state you have? Thus the otherwise distasteful solution of killing the passed in state (by refusing to pass the Bundle given, and instead sending super null) is the only consistently correct thing to do
A good question @DomiR 😅 if there’s some place you just discovered it should go, I/we here may all be missing perspective at this point and so not have thought of it, but github can walk you through a super-quick PR if you hit the edit button at the top of whatever doc page it is
I think this issue can be closed since https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067 is obligatory for the library to work correctly. Comment here if you have any question regarding it.
Just received this crash report
facing same crash here
So hit that edit button and make a PR 😃
@hannigand I think you may have found the one scenario where I still see this problem! Thanks for the location scenario as I do that and I still see crashes sometimes. It seems like we need to abort the entire process of handling the save instance state Bundle. There are few options:
https://stackoverflow.com/questions/6198319/android-how-to-ignore-or-disable-savedinstancestate
It seems like any of these would work:
@hannigand you seem like you’re set up for testing right at this moment, I think we already have a code change as a workaround in MainActivity so focusing on those kind of solutions seems best, want to try either of the two Java changes to see if they work?
Thanks @K-Leon @jgcmarins @joaodematejr for leaving your notes. I’d appreciate it very much if you could find a minute to include a stacktrace from the crash you are experiencing and also version of the library + RN version your app uses.
Agreed. Generally speaking if you cannot save your JS memory (Redux stores, in-component state etc.), then saving only your view state could likely cause inconsistencies.
But then again in a single-activity-app, not saving the activity state means that your app is essentially restarting whenever OS kills your activity for any reason.
Does react-native-navigation attempt to deal with process death challenge, I don’t know. Maybe it’d be better to let to the hosting navigation libraries deal with this. In practice they could keep saving each new screen props on into a bundle in the main activity, put this bundle into the one given in
onSaveInstanceState
and send the data back to as props on activity recreation throughReactRootView.startReactApplication(reactInstanceManager, moduleName, initialProps)
method.Btw my app doesn’t have this problem as we have an architecture (not using this library, but I’d like to in the future) where each screen is an instance of an activity, and the props are sent through converting a ReadableMap into a Bundle and storing the Intent extras. This way we never lose the props at process death, and the props are usually sufficient to recreate the flow the user had left the app in. Not necessarily advocating for multiple activities but just explaining how we solved it.
@lkw1830 you can fix that issue by setting up
screenLayout
&smallestScreenSize
flags inandroid:configChanges
option in yourAndroidManifest.xml
file.So eg. here in our example app https://github.com/software-mansion/react-native-screens/blob/master/Example/android/app/src/main/AndroidManifest.xml#L19
set it as
When I was testing this setting up
screenLayout
flag was sufficient but documentation recommends both of these flags.Source: https://developer.android.com/guide/topics/manifest/activity-element#config
if (outState != null) { outState.clear(); }
- bundle is null onCreate but onResume of activity it has values and that’s your crash@marqroldan I believe it is this one: https://github.com/software-mansion/react-native-screens/issues/463, and there is a solution provided, but it needs to be tested thoroughly: https://github.com/software-mansion/react-native-screens/issues/463#issuecomment-883197624
Tested it with multiple devices as well, seems like a better approach and setup for the readme as suggested.
is it better for the readme?
@iagormoraes the solution works in
ReactActivity
too. You need to still apply this: https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067@sibelius to clarify, if you set the “Don’t keep activites” flag in Developer Options and background & restore your app, does it survive?
Here’s another occurrence with the latest version of screens (alpha 22), with the full stacktrace in a release build.
The exception root is in this line.
@jgcmarins can you please try it with screens@1.0.0-alpha.22 then?
@K-Leon thanks for sending the stacktrace but it is missing the top of the trace (where the exception is specified) which is the most important part. Also if exception has a cause (“caused by” section) that would be an important information too