Background:
Before we were using NavigationExperimental which is JS based navigation. It is now deprecated and that is why we refactored navigation to your library.
Problem:
When Do not keep activities
setting is ON from the Developer Settings the app restarts itself. This happens when home button is pressed to put the app on background. At this point the activity is destroyed since Do not keep activities
is ON. When you go back to the app it starts it from start again and initial state is used.
Also looks like ALL the JS code is run again when activity is destroyed. Redux stores, all files. This should not happen in my opinion. Looks like if I remove this line from this library it does not kill JS which is good. Only problem now is that the navigation state is destroyed and I have to always start from home screen.
When we were using NavigationExperimental this did not happen even when Do not keep activities
was ON. It always remembered where the app was even when activity was destroyed.
So my guess is that react-native-navigation does not resume the state back up when activity is recreated. It always starts everything from scratch when activity is destroyed.
Because Android OS can destroy any activities any time it wants to save memory. We tried this library in production and several users experienced this. So in their case they have used some other memory intensive app which caused OS to kill our app activity.
Android Settings
-> Developer options
-> Do not keep activities
Push Plain Screen
to push new screenYes, this is very critical problem. Should we somehow keep the state always stored in JS side? So when app's activity is redrawn we restore everything in JS side.
Hey guys
This a a very interesting observation. Currently, Js execution is indeed coupled to the Activity which is why Js context is destroyed along with the Activity. We already changed that in V2. I think this change was introduced in RN when HeadlessJs was added, but I might be wrong.
I assume your redux state is already persisted, if that's the case this shouldn't be a major issue.
@guyca Any update on this? I bet this is huge turn off for many people when choosing navigation library. This is the reason we have to use react-navigation at the moment :/
Hey @henrikra
Unfortunately, not much to update. This issue causes quite a few nasty bugs, I agree it should be addressed asap. Will bring this up again with the team and try to allocate time for it asap.
@henrikra @ If anyone want to minimize the app instead of killing it ,
Here's what you need to do .
In NavigationActivity.java , line 172
@Override
public void invokeDefaultOnBackPressed() {
// super.onBackPressed();
this.moveTaskToBack(true); <--add this line
}
And this will do what the homebutton is pressed . (Android only)
@PARAGJYOTI Yeah but what happens when activity is destroyed?
Following this thread. I just realised about something similar.
Note: I am using HeadlessJS
Update: I was able to narrow down the issue a bit more to search for a culprit. I am using https://github.com/ferrannp/react-native-sync-adapter which implements a sync adapter in Android behind the scenes. It receives a HeadlessJS task that gets executed periodically. This is the one causing he issue. I'll try to debug the library to see what's happening.
When I haven't used my app for a while and the OS kills it either for inactivity or lack of resources, when I attempt to open it up again it hangs on the Initial Screen (Splash).
I just tested it by enabling that option in the Developer Settings as the OP mentioned.
Open App => Pressing Home button => OS kills the app => Open App again => App Hangs
When the OS kills the app, those are the logs I get from logcat:
08-09 19:59:35.305 7930-7985/? I/ReactNativeJS: [CodePush] An unknown error occurred.
08-09 19:59:35.305 7930-7985/? I/ReactNativeJS: [CodePush] 400: An update check must include a valid deployment key - please check that your app has been configured correctly. To view available deployment keys, run 'code-push deployment ls <appName> -k'.
08-09 19:59:35.395 7930-7940/? I/art: Background sticky concurrent mark sweep GC freed 58714(2MB) AllocSpace objects, 18(4MB) LOS objects, 1% free, 108MB/110MB, paused 5.961ms total 60.219ms
08-09 19:59:42.716 7930-7985/? W/unknown:React: Tried to enqueue runnable on already finished thread: 'native_modules... dropping Runnable.
08-09 19:59:42.716 7930-7985/? W/MessageQueue: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {1601e64} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {1601e64} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:543)
at android.os.Handler.enqueueMessage(Handler.java:631)
at android.os.Handler.sendMessageAtTime(Handler.java:600)
at android.os.Handler.sendMessageDelayed(Handler.java:570)
at android.os.Handler.post(Handler.java:326)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl.runOnQueue(MessageQueueThreadImpl.java:61)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
at android.os.Looper.loop(Looper.java:148)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:199)
at java.lang.Thread.run(Thread.java:818)
08-09 19:59:42.717 7930-7985/? W/unknown:React: Tried to enqueue runnable on already finished thread: 'native_modules... dropping Runnable.
08-09 19:59:42.717 7930-7985/? W/MessageQueue: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {1601e64} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {1601e64} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:543)
at android.os.Handler.enqueueMessage(Handler.java:631)
at android.os.Handler.sendMessageAtTime(Handler.java:600)
at android.os.Handler.sendMessageDelayed(Handler.java:570)
at android.os.Handler.post(Handler.java:326)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl.runOnQueue(MessageQueueThreadImpl.java:61)
at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
at android.os.Looper.loop(Looper.java:148)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:199)
at java.lang.Thread.run(Thread.java:818)
When I attempt to open the app again and it hangs:
08-09 20:00:47.054 7930-7949/? W/unknown:PackagerConnectionSettings: You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' to forward the debug server's port to the device.
08-09 20:00:47.055 7930-7949/? W/unknown:PackagerConnectionSettings: You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' to forward the debug server's port to the device.
08-09 20:00:47.057 7930-7930/? W/unknown:PackagerConnectionSettings: You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' to forward the debug server's port to the device.
08-09 20:00:47.115 7930-8376/? W/unknown:ReconnectingWebSocket: Couldn't connect to "ws://localhost:8081/message?device=Nexus%205%20-%206.0.1%20-%20API%2023&app=com.rauliyohmc.wondrgo&clientid=devserverhelper", will silently retry
08-09 20:00:47.117 7930-8377/? W/unknown:InspectorPackagerConnection: Couldn't connect to packager, will silently retry
08-09 20:00:47.138 7930-7930/? W/unknown:React: Packager connection already open, nooping.
08-09 20:00:47.138 7930-7930/? W/unknown:React: Inspector connection already open, nooping.
08-09 20:00:47.814 7930-8387/? W/ResourceType: No package identifier when getting value for resource number 0x00000000
Any ideas? This issue should be prioritised imo if this library is stated to be production ready (considering the semver).
CC: @guyca
@rauliyohmc Your issue seems unrelated to this issue.
There is few ways to do it. In general we want to save routers state and restore when after activity recreates.
onSaveInstanceState
and onRestoreInstanceState
of activity; But it has limitation. Application
context or static variable.Hey @henrikra
I merged #1838 which I hope will resolve this issue for you. The issue was that we cleared the react native host when the Activity was destroyed. If you don't clear the host then the Js context will be initialized the next time you open the app, even if the activity was destroyed.
Override clearHostOnActivityDestroy
in MainApplication
:
@Override
public boolean clearHostOnActivityDestroy() {
return false;
}
Modify the way the app is launched. On iOS, keep things as is. On Android, start the app if it's ready - and register a listener which will be invoked if the app is opened and react context is initialized. (For example when activity and destroyed)
if (Platform.OS === 'ios') {
startApp();
} else {
Navigation.isAppLaunched()
.then((appLaunched) => {
if (appLaunched) {
startApp();
}
new NativeEventsReceiver().appLaunched(startApp);
})
}
@guyca, I'm using react native navigation 1.1.216
.
"Do not keep activities" is not enabled in Developer options. But, "sometimes", my app restarts when it is resumed from background, which I hope is because the android OS cleared app's memory. Does my issue relate to this thread? If so, what is the solution for a redux based app using react-native-navigation? If not, what might possibly be going wrong?
@sheshavpd Yes, definitely sounds related. I believe it's fixed by now, so I'm closing the issue.
@guyca I've been searching for this everywhere for the past 3 hours. Please add this to the docs as setup instruction. I believe it will benefit a lot of people.
@guyca, using the solution proposed here solves this problem but introduces two other issues - pressing back from root and then coming back to the app causes the "blank" (Splash?) screen issue on launch and a similar situation when invoking the app from the notification center. Any solution? RNN 1.1.397, RN 0.51.0
@PARAGJYOTI your solution is exactly what I needed!
For everyone looking to minimize the react-native android app, follow those instructions. I wish this was somehow documented in the react-native-navigation docs. Just a line or two!
@guyca I am getting the following error when trying adding
@Override
public boolean clearHostOnActivityDestroy() {
return false;
} in MainApplication
MainApplication.java:26: error: method does not override or implement a method from a supertype
@Override
^
1 error
Can you please help me with this error.
@hrshtmims clearHostOnActivityDestroy() is not a method that can be overrided. You have to modify NavigationApplication.java instead.
FWIW, I ended up not needing any of these solutions. I ended up blowing away node_modules
for an unrelated issue (thanks, misuse of .yarnclean
), checking a couple of version numbers, and things started working again.
For reference:
"dependencies": {
"react": "16.3.1",
"react-native": "~0.55.4",
"react-native-navigation": "^1.1.466",
"react-navigation": "^2.0.4"
}
Noting that trying 16.4.0 was a no-go at this time.
@juanmunozg no that's not correct. You shouldn't modify the source code.
@hrshtmims the reason you get _"method does not override..."_ is because the method signature is not the same as the one in the superclass. Type it out like this (notice the arguments).
@Override
public boolean clearHostOnActivityDestroy(Activity activity) {
return false;
}
@rcidt It worked! Thanks. Please, can you explain what does this code do?
@rcidt @guyca There is an issue with overriding clearHostOnActivityDestroy. When we click on a link from some other application like whatsapp, app successfully opens but doesn't go back to whatsapp after pressing back button. It keeps on starting app in an infinite loop.
Hi ! I'm still getting this issue even by overriding clearHostOnActivityDestroy (). Has someone found another fix for this bug ?
Dependencies :
"react": "16.0.0-alpha.6",
"react-native": "0.43.3",
"react-native-navigation": "1.1.398",
Ok so i solved my problem by downgrading react-native-navigation to "1.1.250". I can't reproduce the issue and my app seems to work pretty fine.
@guyca I have a question around https://github.com/wix/react-native-navigation/issues/1022#issuecomment-329432373
Although this solves the issue when the activity is destroyd, the UX is worse for the case when the app is started from the background and the activity haven鈥檛 been destroyed (without this workaround the navigation state would be kept).
Any suggestions for how to keep the navigation state when the activity wasn鈥檛 destroyed + restart the app when being resumed from a state where the activity was destroyed.
@skovhus did you notice #3688 - does that help you?
Yay, that seems to work!
Just a litte summary after spending quite some time with this issue :
For me https://github.com/wix/react-native-navigation/issues/1022#issuecomment-329432373 , https://github.com/wix/react-native-navigation/issues/1022#issuecomment-397374735 fixes the endless splash screen after the app is killed in the background.
After closing the app with the back button we have the same problem again. A fix for this is overwriting the back handler to minimize the app instead of killing it, for example like this: https://github.com/wix/react-native-navigation/issues/2610#issuecomment-368960868. You have to modify the library code or add the linked command as a postinstall script.
I would recommend https://github.com/wix/react-native-navigation/pull/3688 however, as it fixes all of the issues & is cleaner in my option. Its not merged in yet, so import it in package.json:
"react-native-navigation": "git://github.com/BasitAli/react-native-navigation.git#52ae13ed48a089828813b0c742be244fbf6c8b82"
@guyca, can you explain more about why #1022 (comment) fixes the endless splash screen after the app is killed in the background, thanks!
I've used react-navigtation, not react-native-navigation.
Then how could I modify the way the app is launched, because I didn't find any provision like isAppLaunched() in react-navigtation.
@Avdhutk did you figure our have to solve your issue?
To be clear, I'm still seeing this in the latest version. Here is a GIF of it in action:
Perhaps I'm missing something but it would great if you could shed some light on what needs to be done on master to restore the state when the Activity is destroyed in background.
Thanks!
Most helpful comment
Hey @henrikra
I merged #1838 which I hope will resolve this issue for you. The issue was that we cleared the react native host when the Activity was destroyed. If you don't clear the host then the Js context will be initialized the next time you open the app, even if the activity was destroyed.
Override
clearHostOnActivityDestroy
inMainApplication
:Modify the way the app is launched. On iOS, keep things as is. On Android, start the app if it's ready - and register a listener which will be invoked if the app is opened and react context is initialized. (For example when activity and destroyed)