-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent unwanted app destroy on Android #2043
Conversation
@@ -133,6 +135,7 @@ protected void onNewIntent(Intent intent) { | |||
@Override | |||
protected void onPause() { | |||
super.onPause(); | |||
lastActivity = currentActivity; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're leaking the activity by saving it in a static field after onPause
.
Note that currentActivity
is static, onDestroy
of first activity is called after onResume
of second activity. Perhaps we can change the conditional in destroyJsIfNeeded
to to:
(currentActivity == null || (currentActivity.isFinishing() && currentActivity == this))
this way onDestroyApp
is called only if the finishing activity is the current activity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see ..
The problem is not related to the second part of the conditional but with the first one: currentActivity == null
In fact, if the app is paused between the second screen onResume
and the first screen onDestroy
the currentActivity
will be null and de app will be destroyed.
I will try to find another way to handle this case.
@guyca what about this approach ? Not the best code I wrote but I don't see any other straightforward solution. |
The issue is basically that the react context is lost since |
I already tried that solution and it partially worked, in fact the app does not crash when the permissions are accepted/declined and you can use it without any problem but when you close it with the back button and try to relaunch it, it gets stucked on the SplashScreen. Is it another issue ? Or maybe I miss used this |
Did you modify your Js code accordingly? Promise.resolve(Navigation.isAppLaunched())
.then((appLaunched) => {
if (appLaunched) {
startApp();
}
new NativeEventsReceiver().appLaunched(() => {
// The event is dispatched from SplashActivity and starts the app.
// This flow happens when the app was started while react context was already initialized
startApp();
});
}) I noticed you're incrementing activity count in onCreate and decrementing in onDestroy. This doesn't seem like what you want as the activity can be recreated after onStop |
@@ -151,6 +153,7 @@ protected void onDestroy() { | |||
destroyLayouts(); | |||
destroyJsIfNeeded(); | |||
NavigationApplication.instance.getActivityCallbacks().onActivityDestroyed(this); | |||
numberOfActivities -= 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed you're incrementing activity count in onCreate and decrementing in onDestroy. This doesn't seem like what you want as the activity can be recreated after onStop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You’re right, I was looking at the android Activity Lifecycle and I am afraid I can’t find any way to reliably use this counter.
@guyca I tried your advice and it seems to work on Android :)
@Override
public boolean clearHostOnActivityDestroy() {
return false;
}
import 'react-native';
import { Navigation, NativeEventsReceiver } from 'react-native-navigation';
import app from './src/app';
Promise.resolve(Navigation.isAppLaunched())
.then((appLaunched) => {
if (appLaunched) {
app();
}
new NativeEventsReceiver().appLaunched(() => {
app();
});
}); And everything seems OK ! Except for iOS which throw async function isAppLaunched() {
return Promise.resolve(true);
} or should I update my code and have a different implementation for Android and iOS ? |
This PR is no longer justified, I close it. Thanks for the help @guyca :) |
Hey @eeynard |
Hi,
I was running into an annoying issue while trying to ask user permissions in my home screen on android (I have a map on the home screen so I need to ask the user for his location). I am using react-native-permissions and since it use react-native PermissionsAndroid API you must call the
Permissions.request
function after starting an activity or you will end up with the errorTried to use permissions API while not attached to an Activity
.The problem is that even when you call the
Permissions.request
function in thecomponentDidMount
callback of your home screen, your app ends up crashing when the user accept or decline the permission with the error shown above.So after some investigations I realize that when the native permissions pop up shows up, the app is put in pause and the
currentActivity
is null. I forgot to mention that I have a Login flow first and at the end I callstartSingleScreenApp
so the first activity is destroyed and replaced by the new one. The problem here is that theonDestroy
callback is called after theonPause
of the new screen. So when is get troughdestroyJsIfNeeded
function,currentActivity
is null and the app is destroyed, causing theTried to use permissions API while not attached to an Activity
.I apologize if it is not very clear but it is pretty hard to explain !
I don't have a global view of the project so please tell me if I am doing something wrong.