alwaystest / Blog

24 stars 2 forks source link

Intent.FLAG_ACTIVITY_NEW_TASK #71

Open alwaystest opened 6 years ago

alwaystest commented 6 years ago

Intent.FLAG_ACTIVITY_NEW_TASK

标签(空格分隔): Android


遇到一个奇怪的现象。 设置了Flag启动一个已经在ActivityStack里的Activity。

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

调用过后发现启动的Activity居然被Destroy后重新创建了。 之前一直以为只要这么写,就肯定会调用之前Activity的onNewIntent,起到SingleTask的效果。

官方文档是这么解释的:

https://developer.android.com/guide/components/activities/tasks-and-back-stack.html

FLAG_ACTIVITY_CLEAR_TOP If the activity being started is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it are destroyed and this intent is delivered to the resumed instance of the activity (now on top), through onNewIntent()). There is no value for the launchMode attribute that produces this behavior. FLAG_ACTIVITY_CLEAR_TOP is most often used in conjunction with FLAG_ACTIVITY_NEW_TASK. When used together, these flags are a way of locating an existing activity in another task and putting it in a position where it can respond to the intent. Note: If the launch mode of the designated activity is "standard", it too is removed from the stack and a new instance is launched in its place to handle the incoming intent. That's because a new instance is always created for a new intent when the launch mode is "standard".

原来是AndroidManifest里没有指定Activity的启动模式,默认是standard.

查看ActivityStack的源码:

https://android.googlesource.com/platform/frameworks/base/+/f76a50c/services/java/com/android/server/am/ActivityStack.java

// performClearTaskLocked

// Finally, if this is a normal launch mode (that is, not
// expecting onNewIntent()), then we will finish the current
// instance of the activity so a new fresh one can be started.
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
        && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
    if (!ret.finishing) {
        int index = indexOfTokenLocked(ret.appToken);
        if (index >= 0) {
            finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
                    null, "clear");
        }
        return null;
    }
}

本来以为使用指定Flag的方式启动过一次Activity,这次Activity的launchMode就应该是Flag指定的了,比如AndroidManifest里指定launchMode是standard,通过intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);启动后,新启动的Activity的LaunchMode应该会变成SingleTask。

其实不对,事实证明,通过设置Flag以SingleTask的方式启动standard模式的Activity,不管启动多少次,Activity始终会被销毁重建。

运行下代码查看通过指定Flag启动的Activity的launchMode吧。

    val intent = Intent(this, TestActivity::class.java)
    intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
    startActivity(intent)

在OnCreate的时候断点查看ActivityInfo的launchMode是和Manifest里一致的,Intent里面的Flag并不会被设置到ActivityInfo里面去。

我自己的理解是这样的,以AndroidManifest声明的启动模式为准,如果是默认的standard,说明作者并不想让这个Activity被调用onNewIntent来复用,那就尊重作者的意见,把Activity销毁重建吧。