React Native Android,由于来自后台状态而同时运行的几个应用程序实例,而没有杀死应用程序

时间:2016-09-23 09:14:53

标签: android react-native react-native-android

以下是重现错误的过程。

在我的项目v0.29中发生,但我刚刚在v0.33上测试了一个新的,并且它的行为方式相同。

当应用程序运行时,按下设备/模拟器的主页按钮并通过单击桌面图标打开应用程序,这里发生的是应用程序重新启动安装组件而没有先卸载它,导致如果你多次这样做,应用程序会运行几个实例。

enter image description here

然后,如果您按下设备后退按钮,它将终止并卸载顶级实例,让您使用前一个实例,直到卸下最后一个实例,它将转到桌面。

enter image description here

在此之后如果您退出应用程序,就像您最初按下主页按钮并通过单击桌面图标打开它,这不会重新启动应用程序再次安装它,从这一刻开始正常运行。 同样,如果应用程序首次启动,则使用后退按钮将其退出,之后主页按钮将表现正常。

同样以同样的方式,如果你实现像react-native-activity-android这样的软件包,以避免在按下后退按钮时杀死应用程序,你最终会运行多个应用程序。

enter image description here

enter image description here

我不知道android,当应用程序被杀死时发生了什么事情,如果你使用home按钮将应用程序发送到后台它可以正常工作?

任何想法如何解决这个问题,所以将应用程序发送到后台并重新打开它并不会挂载多个应用程序?

如果我需要在后台运行应用程序以进行位置/通知,假设我无法解决此问题,但我可以处理事件监听器,因此它们不会被执行多次。性能/内存同时安装多个应用程序有多糟糕?

由于

3 个答案:

答案 0 :(得分:8)

此错误是由于React Native为每个应用程序创建了多个活动,导致多个根组件同时运行。

似乎适用于大多数人的解决方案是将launchMode设置为singleInstance AndroidManifest.xml,如下所示:

<manifest>
    ...
    <application>
        ...
        <activity ... android:launchMode="singleInstance">
        </activity>
    </application>
</manifest>

更多信息:

https://github.com/facebook/react-native/issues/10266

https://github.com/facebook/react-native/issues/7079

答案 1 :(得分:1)

事实证明,使用BackAndroid并从后台处理程序返回false会导致组件卸载。当应用程序返回到前台时,需要重建这些组件。

我已尝试将android:launchMode="singleTask"添加到AndroidManifest.xml中的活动,但无济于事。我的解决方案是使用react-native-activity-android,然后根据需要将应用放在后台ActivityAndroid.moveTaskToBack(),而不是return false。您的处理程序将看起来像这样:

handleBackPress() {
    if (this.navigator) {
        if (this.navigator.getCurrentRoutes().length > 1) {
            this.navigator.pop();
        } else {
            ActivityAndroid.moveTaskToBack();
        }
    }
    return true;
};

注意:此插件的作者尚未更新它以与React Native 0.29.0或更高版本兼容。在撰写本文时,我的pull request要解决此问题。

答案 2 :(得分:1)

实际上,您可以实现自己的模块来解决此问题。这很简单。将这段代码添加到您的本机模块中。

@ReactMethod
public void moveTaskToBack(Callback cb) {
    Activity activity = getCurrentActivity();
    boolean wasMoved = activity.moveTaskToBack(true);
    if (cb != null) {
        cb.invoke(wasMoved);
    }
}

然后你可以像Ryan提出的那样处理onBackPress事件。始终返回true并在需要时调用moveTaskToBack()。