Activity 的多个实例

Multiple Instances of Activity

我们已经检查了 CATEGORY_MAIN!isTaskRoot(),但即便如此也启动了 2 个 activity 实例。

SplashActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.i("OnCreate method.");

    if(checkIfActivityIsBroughtToFront() || checkIfActivityIsRootTask()) {
        return; // Found that if we finish and don't return then it will run the code below, hence start the recovery task.
    }

    Log.i("Checking if Recovery is required ...");
    new RecoveryTask(SplashActivity.this, this).execute();
}

private boolean checkIfActivityIsBroughtToFront() {
    if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
        // Activity was brought to front and not created,
        // Thus finishing this will get us to the last viewed activity
        Log.i("Detecting a brought to front, no need for recovery.");
        finish();

        return true;
    }

    return false;
}

private boolean checkIfActivityIsRootTask() {
    if (!isTaskRoot()) {
        final Intent intent = getIntent();
        final String intentAction = intent.getAction();
        if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
            Log.i("Main Activity is not the root. " + "Finishing Main Activity instead of launching.");
            finish();

            return true;
        }
    }

    return false;
}

日志

2015-10-22 13:42:25.581 +0300 SplashActivity INFO[main] - OnCreate method.
2015-10-22 13:42:25.587 +0300 SplashActivity INFO[main] - Checking if Recovery is required ...
2015-10-22 13:42:25.637 +0300 SplashActivity INFO[main] - OnCreate method.
2015-10-22 13:42:25.638 +0300 SplashActivity INFO[main] - Checking if Recovery is required ...
2015-10-22 13:42:25.828 +0300 GeoFenceManager INFO[pool-5-thread-1] - Removing geofences ...
2015-10-22 13:42:25.872 +0300 GeoFenceManager INFO[pool-5-thread-2] - Removing geofences ...

清单

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="x.y.z"
    android:installLocation="internalOnly" >
<application
        android:name=".global.GlobalInstance"
        android:allowBackup="true"
        android:allowClearUserData="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:persistent="true" >

        <activity
            android:name=".activity.SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/Theme.Background" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".receiver.BootUpReceiver"
            android:enabled="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

更新: 这是在重启后发生的,BOOT_COMPLETED 侦听器正在跟随

public class BootUpReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, SplashActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);
    }
}

知道如何避免这种情况吗?

   private boolean checkIfActivityIsRootTask() { 
    if (!isTaskRoot()) {
    final Intent intent = getIntent();
    final String intentAction = intent.getAction();
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
          Log.i("Main Activity is not the root. " + "Finishing Main Activity   instead of launching.");
        finish();

        return true; 
      } 
   } 

return false; 
} ?

如果这个activity是roottask,它return false; RecoveryTask 有什么用?

你说:

We have already the check of CATEGORY_MAIN and !isTaskRoot()

但是两次检查都失败了。在您附加的日志中,当创建两个实例时,Detecting a brought to front, no need for recovery.Main Activity is not the root. " + "Finishing Main Activity instead of launching. 都不会打印在日志中。这意味着在这两种方法中都不会遇到 if 部分,因此 finish() 永远不会被执行。这两种方法都返回 false。

此外,仅仅因为您在 onCreate() 中调用 finish()return,并不意味着 onStart()onResume() 不会打电话。

为什么会这样? 启动器 activity 永远不会被调用两次(考虑到您没有在内部启动 activity)。可能是用户使用的某些 SDK 中的错误。

可能的修复: 您可以尝试在 SplashActivity 的清单中设置 android:launchMode="singleTop"。这将确保只维护一个实例。

将 android:launchMode="SingleTask" 添加到 xml 中的初始 activity 元素。然后离开 activity 即离开启动调用 finish()。您应该使用此模式而不是 "SingleInstance" 的原因是用户永远无法使用后退键导航回启动画面(因为这不是正常行为)。