本文结合demo App和手机的实际情况(dumpsys activity containers),分析一下Activity的启动模式。

一、启动模式

google文档的介绍:

您可以通过启动模式定义 Activity 的新实例如何与当前Task关联。您可以通过两种方式定义不同的启动模式:

使用manifest文件

当您在manifest文件中声明 Activity 时,您可以指定该 Activity 在启动时如何与Task关联。

使用Intent标记

当您调用 startActivity()时,可以在 Intent中添加一个标记,用于声明新 Activity 如何(或是否)与当前Task相关联。

因此,如果 Activity A 启动 Activity B,Activity B 可在其manifest中定义如何与当前Task相关联(如果关联的话),Activity A 也可以请求 Activity B 应该如何与当前Task关联。如果两个 Activity 都定义了 Activity B 应如何与Task关联,将优先遵循 Activity A 的请求(在 intent 中定义),而不是 Activity B 的请求(在manifest中定义)。

注意:有些启动模式可通过manifest文件定义,但不能通过 intent 标记定义,同样,有些启动模式可通过 intent 标记定义,却不能在manifest中定义。

二、使用manifest文件

在manifest文件中声明 Activity 时,可以使用<activity>元素的launchMode属性指定 Activity 应该如何与Task关联。

launchMode属性说明了Activity 应如何启动到Task中。launchMode的定义如下:

<!-- Specify how an activity should be launched.  See the<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and BackStack</a> document for important information on how these options impactthe behavior of your application.<p>If this attribute is not specified, <code>standard</code> launchmode will be used.  Note that the particular launch behavior canbe changed in some ways at runtime through the{@link android.content.Intent} flags{@link android.content.Intent#FLAG_ACTIVITY_SINGLE_TOP},{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}, and{@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. -->
<attr name="launchMode"><enum name="standard" value="0" /><enum name="singleTop" value="1" /><enum name="singleTask" value="2" /><enum name="singleInstance" value="3" /><enum name="singleInstancePerTask" value="4" />
</attr>

launMode有5种:

standard、singleTop、singleTask、singleInstance、singleInstancePerTask。

如果launchMode属性没有指定,那么默认是standard模式。注意在运行时某特殊启动方式可能会被Intent的flag改变。

1 standard

1.1 standard定义

     <!-- The default mode, which will usually create a new instance ofthe activity when it is started, though this behavior may changewith the introduction of other options such as{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASKIntent.FLAG_ACTIVITY_NEW_TASK}. --><enum name="standard" value="0" />

1)、渣翻:

默认模式,通常会在Activity启动时创建一个新的实例,尽管这种行为可能会随着其他选项的引入而改变,比如Intent.FLAG_ACTIVITY_NEW_TASK。

2)、google文档定义:

“standard”(默认模式)

默认值。系统在启动该 Activity 的任务中创建 Activity 的新实例,并将 intent 传送给该实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例。

1.2 standard实际应用

新建一个launchMode声明为standard的Activity,StandardActivity。

以MainActivity为起点,启动StandardActivity,堆栈情况为:

        #6 Task=83 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{9aefb8a u0 com.test.la un ch mo de/.StandardActivity t83} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3c3ba3c u0 com.test.la un ch mo de/.MainActivity t83} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

尝试再次启动StandardActivity一个的新的实例,结果堆栈情况为:

        #6 Task=83 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{9542c1 u0 com.test.la un ch mo de/.StandardActivity t83} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{9aefb8a u0 com.test.la un ch mo de/.StandardActivity t83} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3c3ba3c u0 com.test.la un ch mo de/.MainActivity t83} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

StandardActivity的实例可以被多次创建,因此一个StandardActivity的新实例StandardActivity2被创建并且位于当前Task的top。

2 singleTop

2.1 singleTop定义

     <!-- If, when starting the activity, there is already aninstance of the same activity class in the foreground that isinteracting with the user, thenre-use that instance.  This existing instance will receive a call to{@link android.app.Activity#onNewIntent Activity.onNewIntent()} withthe new Intent that is being started. --><enum name="singleTop" value="1" />

1)、渣翻:

当启动Activity时,在前台已经有一个与用户交互的相同Activity的实例,那么重用该实例。这个已经存在的实例将收到一个对Activity.onNewIntent()}的调用,传参是正在启动的Intent。

2)、google文档定义:

“singleTop”

如果当前任务的顶部已存在 Activity 的实例,则系统会通过调用其onNewIntent()方法来将 intent 转送给该实例,而不是创建 Activity 的新实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例(但前提是返回堆栈顶部的 Activity 不是该 Activity 的现有实例)。

例如,假设任务的返回堆栈包含根 Activity A 以及 Activity B、C 和位于顶部的 D(堆栈为 A-B-C-D;D 位于顶部)。收到以 D 类型 Activity 为目标的 intent。如果 D 采用默认的 “standard” 启动模式,则会启动该类的新实例,并且堆栈将变为 A-B-C-D-D。但是,如果 D 的启动模式为 “singleTop”,则 D 的现有实例会通过onNewIntent()接收 intent,因为它位于堆栈顶部,堆栈仍为 A-B-C-D。但是,如果收到以 B 类型 Activity 为目标的 intent,则会在堆栈中添加 B 的新实例,即使其启动模式为 “singleTop” 也是如此。

注意:创建 Activity 的新实例后,用户可以按返回按钮返回到上一个 Activity。但是,当由 Activity 的现有实例处理新 intent 时,用户将无法通过按返回按钮返回到onNewIntent()收到新 intent 之前的 Activity 状态。

2.2 singleTop实际应用

新建一个launchMode声明为singleTop的Activity,SingleTopActivity。

2.2.1 SingleTopActivity的实例已经处于Task top的情况下启动SingleTopActivity

以MainActivity为起点,启动SingleTopActivity:

        #6 Task=85 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3373d6a u0 com.test.launchmode/.SingleTopActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{d66e925 u0 com.test.launchmode/.MainActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

此时再次尝试启动SingleTopActivity:

由于此时已经有一个SingleTopActivity的实例位于Task的top,因此不会启动一个新的SingleTopActivity,而是处于Task top的这个SingleTopActivity实例收到Activity.onNewIntent回调:

03-01 15:15:45.995  1483  6147 I wm_new_intent: [0,222456063,86,com.test.launchmode/.SingleTopActivity,NULL,NULL,NULL,0]
03-01 15:15:46.028  9926  9926 I wm_on_top_resumed_lost_called: [222456063,com.test.launchmode.SingleTopActivity,pausing]
03-01 15:15:46.029  9926  9926 I wm_on_paused_called: [222456063,com.test.launchmode.SingleTopActivity,performPause]
03-01 15:15:46.029  9926  9926 I launchmode_test: SingleTopActivity#onNewIntent
03-01 15:15:46.030  9926  9926 I wm_on_resume_called: [222456063,com.test.launchmode.SingleTopActivity,LIFECYCLER_RESUME_ACTIVITY]
03-01 15:15:46.030  9926  9926 I wm_on_top_resumed_gained_called: [222456063,com.test.launchmode.SingleTopActivity,topWhenResuming]

2.2.2 SingleTopActivity的实例没有处于Task top的情况下启动SingleTopActivity

接2.2.1,此时再启动一个StandardActivity:

        #6 Task=85 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{7b9e87a u0 com.test.launchmode/.StandardActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3373d6a u0 com.test.launchmode/.SingleTopActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{d66e925 u0 com.test.launchmode/.MainActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

最后在SingleTopActivity不为top的情况再次尝试启动SingleTopActivity:

        #6 Task=85 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#3 ActivityRecord{655dbef u0 com.test.launchmode/.SingleTopActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{7b9e87a u0 com.test.launchmode/.StandardActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3373d6a u0 com.test.launchmode/.SingleTopActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{d66e925 u0 com.test.launchmode/.MainActivity t85} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

这时由于之前启动的SingleTopActivity的实例SingleTopActivity1没有位于top,所以这次会创建一个SingleTopActivity的新实例SingleTopActivity2。

3 singleTask

3.1 singleTask定义

        <!-- If, when starting the activity, there is already a task runningthat starts with this activity, then instead of starting a newinstance the current task is brought to the front.  The existinginstance will receive a call to {@link android.app.Activity#onNewIntentActivity.onNewIntent()}with the new Intent that is being started, and with the{@link android.content.Intent#FLAG_ACTIVITY_BROUGHT_TO_FRONTIntent.FLAG_ACTIVITY_BROUGHT_TO_FRONT} flag set.  This is a supersetof the singleTop mode, where if there is already an instanceof the activity being started at the top of the stack, it willreceive the Intent as described there (without theFLAG_ACTIVITY_BROUGHT_TO_FRONT flag set).  See the<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and BackStack</a> document for more details about tasks.--><enum name="singleTask" value="2" />

1)、渣翻:

当启动该Activity的时候,如果已经有一个正在运行的Task以该Activity启动,那么该Task将被移动到前台,而不是启动一个新的实例。现存的实例将会收到Activity.onNewIntent()方法的调用,传入正在启动的Intent,这个Intent还会被设置Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT。这是singleTop模式的超集。

2)、google文档:

“singleTask”

系统会创建新任务,并实例化新任务的根 Activity。但是,如果另外的任务中已存在该 Activity 的实例,则系统会通过调用其onNewIntent()方法将 intent 转送到该现有实例,而不是创建新实例。Activity 一次只能有一个实例存在。

注意:虽然 Activity 在新任务中启动,但用户按返回按钮仍会返回到上一个 Activity。

再举个例子,Android 浏览器应用在元素中指定 singleTask 启动模式,由此声明网络浏览器 Activity 应始终在它自己的任务中打开。这意味着,如果您的应用发出打开 Android 浏览器的 intent,系统不会将其 Activity 置于您的应用所在的任务中,而是会为浏览器启动一个新任务,如果浏览器已经有任务在后台运行,则会将该任务转到前台来处理新 intent。

无论 Activity 是在新任务中启动的,还是在和启动它的 Activity 相同的任务中启动,用户按返回按钮都会回到上一个 Activity。但是,如果您启动了指定 singleTask 启动模式的 Activity,而后台任务中已存在该 Activity 的实例,则系统会将该后台任务整个转到前台运行。此时,返回堆栈包含了转到前台的任务中的所有 Activity,这些 Activity 都位于堆栈的顶部。图 4 展示了具体的情景。

图 4. 采用“singleTask”启动模式的 Activity 添加到返回堆栈的过程图示。如果 Activity 已经存在于某个具有自己的返回堆栈的后台任务中,那么整个返回堆栈也会转到前台,覆盖当前任务。

要详细了解如何在清单文件中设置启动模式,请参阅元素的说明文档,里面详细介绍了 launchMode 属性和可接受的值。

注意:您通过launchMode属性为 Activity 指定的行为,可被启动 Activity 的 intent 所包含的标记替换。

3.2 singleTask实际应用

新建一个launchMode声明为singleTask的Activity,SingleTaskActivity。

3.2.1 启动SingleTaskActivity

以MainActivity为起点:

        #6 Task=100 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14b21d2 u0 com.test.launchmode/.MainActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

启动SingleTaskActivity:

        #6 Task=100 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{f14ffea u0 com.test.launchmode/.SingleTaskActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14b21d2 u0 com.test.launchmode/.MainActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

新实例仍然在Task#100中,并没有想象中那样为SingleTaskActivity创建一个新的Task。

3.2.2 SingleTaskActivity已经处于当前Task的top的情况下启动SingleTaskActivity

接3.2.1,此时再次尝试启动SingleTaskActivity:

由于此时已经有一个SingleTaskActivity的实例位于Task的top,因此不会启动一个新的SingleTaskActivity,而是处于Task top的这个SingleTaskActivity实例收到Activity.onNewIntent回调:

03-01 17:50:11.789  1483  6167 I wm_new_intent: [0,253034474,100,com.test.launchmode/.SingleTaskActivity,NULL,NULL,NULL,268435456]
03-01 17:50:11.791  1483  6167 I wm_task_moved: [100,1,6]
03-01 17:50:11.796  1483  6167 I wm_set_resumed_activity: [0,com.test.launchmode/.SingleTaskActivity,positionChildAt]
03-01 17:50:11.842 15874 15874 I wm_on_top_resumed_lost_called: [253034474,com.test.launchmode.SingleTaskActivity,pausing]
03-01 17:50:11.843 15874 15874 I wm_on_paused_called: [253034474,com.test.launchmode.SingleTaskActivity,performPause]
03-01 17:50:11.843 15874 15874 I launchmode_test: SingleTaskActivity#onNewIntent
03-01 17:50:11.844 15874 15874 I wm_on_resume_called: [253034474,com.test.launchmode.SingleTaskActivity,LIFECYCLER_RESUME_ACTIVITY]
03-01 17:50:11.845 15874 15874 I wm_on_top_resumed_gained_called: [253034474,com.test.launchmode.SingleTaskActivity,topWhenResuming]

3.2.3 SingleTaskActivity没有处于当前Task的top的情况下启动SingleTaskActivity

接3.2.2,启动一个StandardActivity:

        #6 Task=100 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{c901e6c u0 com.test.launchmode/.StandardActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{f14ffea u0 com.test.launchmode/.SingleTaskActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14b21d2 u0 com.test.launchmode/.MainActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

然后再尝试启动SingleTaskActivity:

        #6 Task=100 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{f14ffea u0 com.test.launchmode/.SingleTaskActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14b21d2 u0 com.test.launchmode/.MainActivity t100} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

之前启动的StandardActivity被销毁,SingleTaskActivity没有被重新创建,而是旧的实例收到Activity.onNewIntent回调。

03-01 17:52:13.212  1483  1500 I wm_finish_activity: [0,210771564,100,com.test.launchmode/.StandardActivity,clear-task-stack]
03-01 17:52:13.217  1483  1500 I wm_pause_activity: [0,210771564,com.test.launchmode/.StandardActivity,userLeaving=false,finish]
03-01 17:52:13.221  1483  1500 I wm_new_intent: [0,253034474,100,com.test.launchmode/.SingleTaskActivity,NULL,NULL,NULL,268435456]
03-01 17:52:13.222  1483  1500 I wm_task_moved: [100,1,6]
03-01 17:52:13.310 15874 15874 I wm_on_top_resumed_lost_called: [210771564,com.test.launchmode.StandardActivity,topStateChangedWhenResumed]
03-01 17:52:13.325 15874 15874 I wm_on_paused_called: [210771564,com.test.launchmode.StandardActivity,performPause]
03-01 17:52:13.330  1483  9284 I wm_add_to_stopping: [0,210771564,com.test.launchmode/.StandardActivity,completeFinishing]
03-01 17:52:13.379  1483  9284 I wm_set_resumed_activity: [0,com.test.launchmode/.SingleTaskActivity,resumeTopActivityInnerLocked]
03-01 17:52:13.470  1483  9284 I wm_resume_activity: [0,253034474,100,com.test.launchmode/.SingleTaskActivity]
03-01 17:52:13.577 15874 15874 I wm_on_restart_called: [253034474,com.test.launchmode.SingleTaskActivity,performRestartActivity]
03-01 17:52:13.577 15874 15874 I wm_on_start_called: [253034474,com.test.launchmode.SingleTaskActivity,handleStartActivity]
03-01 17:52:13.578 15874 15874 I launchmode_test: SingleTaskActivity#onNewIntent
03-01 17:52:13.579 15874 15874 I wm_on_resume_called: [253034474,com.test.launchmode.SingleTaskActivity,RESUME_ACTIVITY]
03-01 17:52:13.579 15874 15874 I wm_on_top_resumed_gained_called: [253034474,com.test.launchmode.SingleTaskActivity,topWhenResuming]
03-01 17:52:14.229  1483  1508 I wm_destroy_activity: [0,210771564,100,com.test.launchmode/.StandardActivity,finish-imm:idle]
03-01 17:52:14.363 15874 15874 I wm_on_stop_called: [210771564,com.test.launchmode.StandardActivity,LIFECYCLER_STOP_ACTIVITY]
03-01 17:52:14.365 15874 15874 I wm_on_destroy_called: [210771564,com.test.launchmode.StandardActivity,performDestroy]

和Intent.FLAG_ACTIVITY_CLEAR_TOP是一样的效果。

3.2.4 启动设置了不同的taskAffinity的SingleTaskActivity

在3.2.1中,我本来以为创建SingleTaskActivity的时候,会为其创建一个新的Task,但是实际上SingleTaskActivity还是在现有的Task中启动了。跟了一下Activity启动的流程,发现,如果正在启动的Activity的taskAffinity和现存的某个Task的rootAffinity成员变量符合,那么这个Activity是有可能启动到这个Task中的,而不会去创建新的Task。

查看一下taskAffinity的定义:

    <!-- Specify a task name that activities have an "affinity" to.Use with the application tag (to supply a default affinity for allactivities in the application), or with the activity tag (to supplya specific affinity for that component).<p>The default value for this attribute is the same as the packagename, indicating that all activities in the manifest should generallybe considered a single "application" to the user.  You can use thisattribute to modify that behavior: either giving them an affinityfor another task, if the activities are intended to be part of thattask from the user's perspective, or using an empty string foractivities that have no affinity to a task. --><attr name="taskAffinity" format="string" />

渣翻:指定Activity具有“亲和性”的Task名称。与应用程序标签一起使用(为应用程序中的所有Activity提供默认的affinity),或与Activity标签一起使用(为该组件提供特定的affinity)。此属性的默认值与包名相同,表明manifest中的所有Activity通常应该被用户视为单个“应用程序”。您可以使用此属性来修改该行为:如果从用户的角度来看,Activity是另外的一个Task的一部分,则为Activity提供一个另外一个Task的affinity,或者为没有与任何Task关联的Activity使用一个空字符串。

SingleTaskActivity由于没有显式指定一个taskAffinity属性,因此用的就是默认的包名,即”com.test.launchmode“,所以就会启动到现有的Task中。

这里我们修改SingleTaskActivity的taskAffinity属性:

android:taskAffinity="com.single.task"

以MainActivity为起点,再尝试启动SingleTaskActivity:

        #7 Task=107 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e7a99fa u0 com.test.launchmode/.SingleTaskActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=106 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{94a375c u0 com.test.launchmode/.MainActivity t106} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

果然设置了一个独特的taskAffinity,SingleTaskActivity就可以启动到另外一个Task中。

3.2.5 SingleTaskActivity的一个实例存在于某个后台Task中时从前台Task启动SingleTaskActivity

接3.2.4,通过SingleTaskActivity启动StandardActivity:

       #7 Task=107 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{b2c985e u0 com.test.launchmode/.StandardActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e7a99fa u0 com.test.launchmode/.SingleTaskActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=106 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{94a375c u0 com.test.launchmode/.MainActivity t106} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

新的StandardActivity启动到了SingleTaskActivity所在的Task中。

然后将MainActivity所在的Task移动到前台:

        #7 Task=106 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{94a375c u0 com.test.launchmode/.MainActivity t106} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#5 Task=107 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{b2c985e u0 com.test.launchmode/.StandardActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e7a99fa u0 com.test.launchmode/.SingleTaskActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

再次尝试通过MainActivity去启动SingleTaskActivity:

        #7 Task=107 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e7a99fa u0 com.test.launchmode/.SingleTaskActivity t107} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=106 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{94a375c u0 com.test.launchmode/.MainActivity t106} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

SingleTaskActivity所在的Task#107移动到前台,SingleTaskActivity收到Activity.onNewIntent回调,并且StandardActivity被干掉:

03-01 19:10:58.807  1483  1501 I wm_task_moved: [107,1,7]
03-01 19:10:58.807  1483  1501 I wm_task_to_front: [0,107]
03-01 19:10:58.815  1483  1501 I wm_focused_root_task: [0,0,107,106,bringingFoundTaskToFront]
03-01 19:10:58.829  1483  1501 I wm_set_resumed_activity: [0,com.test.launchmode/.StandardActivity,bringingFoundTaskToFront]
03-01 19:10:58.833  1483  1501 I wm_finish_activity: [0,187471966,107,com.test.launchmode/.StandardActivity,clear-task-stack]
03-01 19:10:58.834  1483  1501 I wm_destroy_activity: [0,187471966,107,com.test.launchmode/.StandardActivity,finish-imm:finishIfPossible]
03-01 19:10:58.839  1483  1501 I wm_new_intent: [0,242915834,107,com.test.launchmode/.SingleTaskActivity,NULL,NULL,NULL,268435456]
03-01 19:10:58.855  1483  1501 I wm_pause_activity: [0,155858780,com.test.launchmode/.MainActivity,userLeaving=true,pauseBackTasks]
03-01 19:10:58.920 20840 20840 I wm_on_top_resumed_lost_called: [155858780,com.test.launchmode.MainActivity,topStateChangedWhenResumed]
03-01 19:10:58.948 20840 20840 I wm_on_destroy_called: [187471966,com.test.launchmode.StandardActivity,performDestroy]
03-01 19:10:59.080 20840 20840 I wm_on_paused_called: [155858780,com.test.launchmode.MainActivity,performPause]
03-01 19:10:59.169  1483  1501 I wm_set_resumed_activity: [0,com.test.launchmode/.SingleTaskActivity,resumeTopActivityInnerLocked]
03-01 19:10:59.177  1483  1501 I wm_add_to_stopping: [0,155858780,com.test.launchmode/.MainActivity,makeInvisible]
03-01 19:10:59.216  1483  1501 I wm_resume_activity: [0,242915834,107,com.test.launchmode/.SingleTaskActivity]
03-01 19:10:59.308 20840 20840 I wm_on_restart_called: [242915834,com.test.launchmode.SingleTaskActivity,performRestartActivity]
03-01 19:10:59.309 20840 20840 I wm_on_start_called: [242915834,com.test.launchmode.SingleTaskActivity,handleStartActivity]
03-01 19:10:59.309 20840 20840 I launchmode_test: SingleTaskActivity#onNewIntent
03-01 19:10:59.310 20840 20840 I wm_on_resume_called: [242915834,com.test.launchmode.SingleTaskActivity,RESUME_ACTIVITY]
03-01 19:10:59.310 20840 20840 I wm_on_top_resumed_gained_called: [242915834,com.test.launchmode.SingleTaskActivity,topWhenResuming]
03-01 19:11:00.645  1483  1508 I wm_stop_activity: [0,155858780,com.test.launchmode/.MainActivity]
03-01 19:11:00.789 20840 20840 I wm_on_stop_called: [155858780,com.test.launchmode.MainActivity,STOP_ACTIVITY_ITEM]

销毁StandardActivity的逻辑和3.2.3是一样的。

4 singleInstance

4.1 singleInstance定义

     <!-- Only allow one instance of this activity to ever berunning.  This activity gets a unique task with only itself runningin it; if it is ever launched again with the same Intent, then thattask will be brought forward and its{@link android.app.Activity#onNewIntent Activity.onNewIntent()}method called.  If thisactivity tries to start a new activity, that new activity will belaunched in a separate task.  See the<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and BackStack</a> document for more details about tasks.--><enum name="singleInstance" value="3" />

1)、渣翻:

这个Activity只允许运行一个实例。这个Activity得到一个唯一的Task,只有它自己在运行;如果它再次以相同的Intent启动,那么该Task将会被移动到前台,并且它的Activity.onNewIntent()方法被调用。如果这个Activity尝试启动一个新Activity,这个新活动将在一个单独的Task中启动。

2)、google文档:

“singleInstance”

与 “singleTask” 相似,唯一不同的是系统不会将任何其他 Activity 启动到包含该实例的任务中。该 Activity 始终是其任务唯一的成员;由该 Activity 启动的任何 Activity 都会在其他的任务中打开。

4.2 singleInstance实际应用

新建一个launchMode声明为singleInstance的Activity,SingleInstanceActivity。

4.2.1 启动SingleInstanceActivity

以MainActivity为起点:

        #6 Task=94 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{a19254e u0 com.test.launchmode/.MainActivity t94} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

启动SingleInstanceActivity:

        #7 Task=95 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3211027 u0 com.test.launchmode/.SingleInstanceActivity t95} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=94 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{a19254e u0 com.test.launchmode/.MainActivity t94} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

此时为新启动的SingleInstanceActivity创建了一个新的Task#95,并且Task#95移动到前台。

4.2.2 在非SingleInstanceActivity所在的Task尝试创建一个新的SingleInstanceActivity实例

接4.2.1,切换到MainActivity所在的Task#94:

        #7 Task=94 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{eea3b93 u0 com.test.launchmode/.MainActivity t94} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=95 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3211027 u0 com.test.launchmode/.SingleInstanceActivity t95} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

在MainActivity界面再次尝试启动SingleInstanceActivity:

        #7 Task=95 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3211027 u0 com.test.launchmode/.SingleInstanceActivity t95} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=94 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{eea3b93 u0 com.test.launchmode/.MainActivity t94} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

之前创建的那个SingleInstanceActivity实例所在的Task#95整个被移动到前台,并不会再创建一个新的实例。

4.2.3 在SingleInstanceActivity所在的Task尝试创建一个新的SingleInstanceActivity实例

接4.2.2,再尝试启动SingleInstanceActivity:

结果是并不会创建一个新的实例,只有SingleInstanceActivity收到Activity.onNewIntent回调:

03-01 16:34:55.132  1483  1710 I wm_new_intent: [0,52498471,95,com.test.launchmode/.SingleInstanceActivity,NULL,NULL,NULL,268435456]
03-01 16:34:55.135  1483  1710 I wm_task_moved: [95,1,7]
03-01 16:34:55.142  1483  1710 I wm_set_resumed_activity: [0,com.test.launchmode/.SingleInstanceActivity,positionChildAt]
03-01 16:34:55.195 12995 12995 I wm_on_top_resumed_lost_called: [52498471,com.test.launchmode.SingleInstanceActivity,pausing]
03-01 16:34:55.196 12995 12995 I wm_on_paused_called: [52498471,com.test.launchmode.SingleInstanceActivity,performPause]
03-01 16:34:55.196 12995 12995 I launchmode_test: SingleInstance#onNewIntent
03-01 16:34:55.196 12995 12995 I wm_on_resume_called: [52498471,com.test.launchmode.SingleInstanceActivity,LIFECYCLER_RESUME_ACTIVITY]
03-01 16:34:55.196 12995 12995 I wm_on_top_resumed_gained_called: [52498471,com.test.launchmode.SingleInstanceActivity,topWhenResuming]

4.2.4 在SingleInstanceActivity所在的Task启动其他Activity

以SingleInstanceActivity为起点:

        #6 Task=98 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e074c42 u0 com.test.launchmode/.SingleInstanceActivity t98} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

启动StandardActivity:

        #7 Task=99 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{47012ae u0 com.test.launchmode/.StandardActivity t99} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=98 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{e074c42 u0 com.test.launchmode/.SingleInstanceActivity t98} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

StandardActivity在一个新的Task,Task#99中被启动。

5 singleInstancePerTask

5.1 singleInstancePerTask定义

Android 12新增。

        <!-- The activity can only be running as the root activity of the task, the first activitythat created the task, and therefore there will only be one instance of this activityin a task. In constrast to the {@code singleTask} launch mode, this activity can bestarted in multiple instances in different tasks if the{@code } or {@code FLAG_ACTIVITY_NEW_DOCUMENT} is set.--><enum name="singleInstancePerTask" value="4" />

渣翻:

该Activity只能作为Task的root Activity运行,即创建该Task的第一个Activity,因此在一个Task中只能有一个该Activity的实例。与singleTask启动模式相比,如果设置了FLAG_ACTIVITY_MULTIPLE_TASK或FLAG_ACTIVITY_NEW_DOCUMENT,这个activity可以在不同的Task中多个实例中启动。

5.2 singleInstancePerTask实际应用

新建一个launchMode声明为singleInstancePerTask的Activity,SingleInstancePerTaskActivity。

5.2.1 启动SingleInstancePerTaskActivity

以MainActivity为起点,启动SingleInstancePerTaskActivity:

        #7 Task=230 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{91f591f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=229 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{37dc04d u0 com.test.launchmodetest/.MainActivity t229} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

看到这里直接为新启动的SingleInstancePerTaskActivity创建了一个新的Task#230,而无需为其设置一个不同的taskAffinity。

5.2.2 当SingleInstancePerTaskActivity位于当前Task top时启动SingleInstancePerTaskActivity

接5.2.1,当启动了SingleInstancePerTaskActivity,且为其创建了一个Task#230后,尝试再启动SingleInstancePerTaskActivity,发现SingleInstancePerTaskActivity不会重复启动,而是现有的实例收到Activity.onNewIntent回调:

03-03 09:52:40.023  1490  1723 I wm_new_intent: [0,153049375,230,com.test.launchmodetest/.SingleInstancePerTaskActivity,NULL,NULL,NULL,268435456]
03-03 09:52:40.025  1490  1723 I wm_task_moved: [230,1,7]
03-03 09:52:40.030  1490  1723 I wm_set_resumed_activity: [0,com.test.launchmodetest/.SingleInstancePerTaskActivity,positionChildAt]
03-03 09:52:40.076 30409 30409 I wm_on_top_resumed_lost_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,pausing]
03-03 09:52:40.077 30409 30409 I wm_on_paused_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,performPause]
03-03 09:52:40.077 30409 30409 I launchmode_test: SingleInstancePerTaskActivity#onNewIntent
03-03 09:52:40.078 30409 30409 I wm_on_resume_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,LIFECYCLER_RESUME_ACTIVITY]
03-03 09:52:40.079 30409 30409 I wm_on_top_resumed_gained_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,topWhenResuming]

5.2.3 当SingleInstancePerTaskActivity没有位于当前Task top时启动SingleInstancePerTaskActivity

接5.2.1,先通过SingleInstancePerTaskActivity创建一个StandardActivity:

     #7 Task=230 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{eea3628 u0 com.test.launchmodetest/.StandardActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{91f591f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

然后再去启动SingleInstancePerTaskActivity:

        #7 Task=230 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{91f591f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

结果是StandardActivity被销毁,SingleInstancePerTaskActivity现有的实例收到Activity.onNewIntent回调:

03-03 09:58:44.128  1490  3749 I wm_finish_activity: [0,250230312,230,com.test.launchmodetest/.StandardActivity,clear-task-stack]
03-03 09:58:44.133  1490  3749 I wm_pause_activity: [0,250230312,com.test.launchmodetest/.StandardActivity,userLeaving=false,finish]
03-03 09:58:44.137  1490  3749 I wm_new_intent: [0,153049375,230,com.test.launchmodetest/.SingleInstancePerTaskActivity,NULL,NULL,NULL,268435456]
03-03 09:58:44.138  1490  3749 I wm_task_moved: [230,1,7]
03-03 09:58:44.207 30409 30409 I wm_on_top_resumed_lost_called: [250230312,com.test.launchmodetest.StandardActivity,topStateChangedWhenResumed]
03-03 09:58:44.214 30409 30409 I wm_on_paused_called: [250230312,com.test.launchmodetest.StandardActivity,performPause]
03-03 09:58:44.226  1490  2226 I wm_add_to_stopping: [0,250230312,com.test.launchmodetest/.StandardActivity,completeFinishing]
03-03 09:58:44.248  1490  2226 I wm_set_resumed_activity: [0,com.test.launchmodetest/.SingleInstancePerTaskActivity,resumeTopActivityInnerLocked]
03-03 09:58:44.287  1490  2226 I wm_resume_activity: [0,153049375,230,com.test.launchmodetest/.SingleInstancePerTaskActivity]
03-03 09:58:44.369 30409 30409 I wm_on_restart_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,performRestartActivity]
03-03 09:58:44.369 30409 30409 I wm_on_start_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,handleStartActivity]
03-03 09:58:44.370 30409 30409 I launchmode_test: SingleInstancePerTaskActivity#onNewIntent
03-03 09:58:44.370 30409 30409 I wm_on_resume_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,RESUME_ACTIVITY]
03-03 09:58:44.370 30409 30409 I wm_on_top_resumed_gained_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,topWhenResuming]
03-03 09:58:44.969  1490  1515 I wm_destroy_activity: [0,250230312,230,com.test.launchmodetest/.StandardActivity,finish-imm:idle]
03-03 09:58:45.104 30409 30409 I wm_on_stop_called: [250230312,com.test.launchmodetest.StandardActivity,LIFECYCLER_STOP_ACTIVITY]
03-03 09:58:45.105 30409 30409 I wm_on_destroy_called: [250230312,com.test.launchmodetest.StandardActivity,performDestroy]

5.2.4 当SingleInstancePerTaskActivity存在的Task没有处于前台时去启动SingleInstancePerTaskActivity

接5.2.1,先通过SingleInstancePerTaskActivity创建一个StandardActivity,然后将Task切换到Task#229:

        #7 Task=229 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{37dc04d u0 com.test.launchmodetest/.MainActivity t229} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=230 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{db261fd u0 com.test.launchmodetest/.StandardActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{91f591f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

然后通过Task#229的MainActivity再去启动SingleInstancePerTaskActivity:

        #7 Task=230 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{91f591f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t230} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=229 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{37dc04d u0 com.test.launchmodetest/.MainActivity t229} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

结果Task#230移动到前台,并且StandardActivity被销毁,SingleInstancePerTaskActivity现有的实例收到Activity.onNewIntent回调:

03-03 10:02:35.383  1490  8118 I wm_task_moved: [230,1,7]
03-03 10:02:35.384  1490  8118 I wm_task_to_front: [0,230]
03-03 10:02:35.402  1490  8118 I wm_focused_root_task: [0,0,230,229,bringingFoundTaskToFront]
03-03 10:02:35.427  1490  8118 I wm_set_resumed_activity: [0,com.test.launchmodetest/.StandardActivity,bringingFoundTaskToFront]
03-03 10:02:35.430  1490  8118 I wm_finish_activity: [0,229794301,230,com.test.launchmodetest/.StandardActivity,clear-task-stack]
03-03 10:02:35.431  1490  8118 I wm_destroy_activity: [0,229794301,230,com.test.launchmodetest/.StandardActivity,finish-imm:finishIfPossible]
03-03 10:02:35.434  1490  8118 I wm_new_intent: [0,153049375,230,com.test.launchmodetest/.SingleInstancePerTaskActivity,NULL,NULL,NULL,268435456]
03-03 10:02:35.447  1490  8118 I wm_pause_activity: [0,58572877,com.test.launchmodetest/.MainActivity,userLeaving=true,pauseBackTasks]
03-03 10:02:35.489 30409 30409 I wm_on_top_resumed_lost_called: [58572877,com.test.launchmodetest.MainActivity,topStateChangedWhenResumed]
03-03 10:02:35.513 30409 30409 I wm_on_destroy_called: [229794301,com.test.launchmodetest.StandardActivity,performDestroy]
03-03 10:02:35.562 30409 30409 I wm_on_paused_called: [58572877,com.test.launchmodetest.MainActivity,performPause]
03-03 10:02:35.728  1490  2524 I wm_set_resumed_activity: [0,com.test.launchmodetest/.SingleInstancePerTaskActivity,resumeTopActivityInnerLocked]
03-03 10:02:35.749  1490  2524 I wm_add_to_stopping: [0,58572877,com.test.launchmodetest/.MainActivity,makeInvisible]
03-03 10:02:35.833  1490  2524 I wm_resume_activity: [0,153049375,230,com.test.launchmodetest/.SingleInstancePerTaskActivity]
03-03 10:02:35.949 30409 30409 I wm_on_restart_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,performRestartActivity]
03-03 10:02:35.949 30409 30409 I wm_on_start_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,handleStartActivity]
03-03 10:02:35.950 30409 30409 I launchmode_test: SingleInstancePerTaskActivity#onNewIntent
03-03 10:02:35.950 30409 30409 I wm_on_resume_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,RESUME_ACTIVITY]
03-03 10:02:35.951 30409 30409 I wm_on_top_resumed_gained_called: [153049375,com.test.launchmodetest.SingleInstancePerTaskActivity,topWhenResuming]
03-03 10:02:37.430  1490  1515 I wm_stop_activity: [0,58572877,com.test.launchmodetest/.MainActivity]
03-03 10:02:37.829 30409 30409 I wm_on_stop_called: [58572877,com.test.launchmodetest.MainActivity,STOP_ACTIVITY_ITEM]

5.2.5 结合Intent.FLAG_ACTIVITY_MULTIPLE_TASK和Intent.FLAG_ACTIVITY_NEW_DOCUMENT

分析了上面四种情况,发现singleInstancePerTask的作用和singleTask几乎一样,不过singleInstancePerTask不需要为启动的Activity设置一个特殊的taskAffinity才能创建一个新的Task。

根据singleInstancePerTask的定义,该launchMode和Intent.FLAG_ACTIVITY_MULTIPLE_TASK或Intent.FLAG_ACTIVITY_NEW_DOCUMENT结合使用可以将启动的Activity在多个Task中多次实例化,那么来看具体是怎么样的。这里每次启动SingleInstancePerTaskActivity时,都为启动Intent添加这两个flag:

intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);

还是以MainActivity为起点,然后启动singleInstancePerTask,根据5.2.1,知道此时会为新启动的singleInstancePerTask创建一个Task:

        #7 Task=236 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3a0de63 u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t236} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=235 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{766c588 u0 com.test.launchmodetest/.MainActivity t235} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

接着通过singleInstancePerTask再去启动singleInstancePerTask:

        #8 Task=237 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{518568f u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t237} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#7 Task=236 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{3a0de63 u0 com.test.launchmodetest/.SingleInstancePerTaskActivity t236} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=235 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{766c588 u0 com.test.launchmodetest/.MainActivity t235} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

果然不同于5.2.2,这里又创建了一个singleInstancePerTask的新实例,且创建了一个新的Task#237。

三、使用 Intent 标记

启动 Activity 时,通过在startActivity()的 intent 中添加相应的flag来修改 Activity 与其Task的默认关联。

1 FLAG_ACTIVITY_NEW_TASK

1.1 FLAG_ACTIVITY_NEW_TASK定义

    /*** If set, this activity will become the start of a new task on this* history stack.  A task (from the activity that started it to the* next task activity) defines an atomic group of activities that the* user can move to.  Tasks can be moved to the foreground and background;* all of the activities inside of a particular task always remain in* the same order.  See* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back* Stack</a> for more information about tasks.** <p>This flag is generally used by activities that want* to present a "launcher" style behavior: they give the user a list of* separate things that can be done, which otherwise run completely* independently of the activity launching them.** <p>When using this flag, if a task is already running for the activity* you are now starting, then a new activity will not be started; instead,* the current task will simply be brought to the front of the screen with* the state it was last in.  See {@link #FLAG_ACTIVITY_MULTIPLE_TASK} for a flag* to disable this behavior.** <p>This flag can not be used when the caller is requesting a result from* the activity being launched.*/public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000;

1)、渣翻:
如果设置,这个Activity将成为一个新Task的堆栈中起始Activity。一个Task(从启动它的Activity到下一个Task Activity)定义了一个用户可以移动到的原子Activity组。Task可以移动到前台和后台;特定Task中的所有Activity始终保持相同的顺序。

这个flag通常被想要呈现一个”Launcher”风格行为的Activity使用:它们给用户一个可以做的单独事情的列表,否则这些事情完全独立于启动它们的Activity运行。
当使用这个flag时,如果一个task已经正在运行你启动的activity,那么一个新的activity将不会被启动;相反,当前Task将简单地伴随着它最后一次进入的状态被带到屏幕前面。参见FLAG_ACTIVITY_MULTIPLE_TASK来禁用此行为。

当调用者从启动的Activity请求一个结果时,不能使用此flag。

2)、google文档:

FLAG_ACTIVITY_NEW_TASK

在新Task中启动 Activity。如果您现在启动的 Activity 已经有Task在运行,则系统会将该Task转到前台并恢复其最后的状态,而 Activity 将在onNewIntent()中收到新的 intent。

这与 “singleTask” launchMode值产生的行为相同。

1.2 FLAG_ACTIVITY_NEW_TASK实际应用

1.2.1 以FLAG_ACTIVITY_NEW_TASK的方式启动Activity

这里我直接用MainActivty启动StandardActivity,启动Intent中加入FLAG_ACTIVITY_NEW_TASK:

        #6 Task=134 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{bf67e76 u0 com.test.launchmode/.StandardActivity t134} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{887cfac u0 com.test.launchmode/.MainActivity t134} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

新启动的StandardActivity并没有像预料那样以一个新Task的方式启动,而是仍然创建在了当前Task#134中。

1.2.2 在要启动的Activity已经位于Task的top的情况下以FLAG_ACTIVITY_NEW_TASK的方式启动Activity

接1.2.1,当已经有一个StandardActivity位于当前Task的top时,再去以FLAG_ACTIVITY_NEW_TASK的方式启动StandardActivity:

        #6 Task=134 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{4ced944 u0 com.test.launchmode/.StandardActivity t193} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{bf67e76 u0 com.test.launchmode/.StandardActivity t134} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{887cfac u0 com.test.launchmode/.MainActivity t134} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

和launchMode为“singleTask”的情况也不一样,直接创建了一个新实例,singleTask则是复用了旧实例。

1.2.3 以FLAG_ACTIVITY_NEW_TASK的方式启动一个taskAffinity与App包名不同的Activity

根据google文档的描述,FLAG_ACTIVITY_NEW_TASK产生的行为与launchMode中的singleTask相同,那么没有创建新的Task的原因应该也是一样的,因此我这里新建了一个DifferentAffinityActivity,给它设置一个不同于App包名的taskAffinity,然后通过MainActivity以FLAG_ACTIVITY_NEW_TASK的方式去启动DifferentAffinityActivity:

        #7 Task=2 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{dc31b80 u0 com.test.launchmodetest/.DifferentAffinityActivity t210} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=1 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{ecdd154 u0 com.test.launchmodetest/.MainActivity t209} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

成功,系统为StandardActivity创建了一个Task#2。

另外试验,如果只是为DifferentAffinityActivity设置一个特殊的taskAffinity,但是启动它的时候不设置FLAG_ACTIVITY_NEW_TASK,是不会创建新Task的。

1.2.4 在taskAffinity不同的Task中以FLAG_ACTIVITY_NEW_TASK启动Activity(1)

先启动MainActivity,然后再通过MainActivity以FLAG_ACTIVITY_NEW_TASK的方式启动一个StandardActivity,根据1.2.1可知,这两个Activity会在同一个Task中。

接着通过StandardActivity以FLAG_ACTIVITY_NEW_TASK的方式启动一个不同taskAffinity的DifferentAffinityActivity,根据1.2.3可知,系统会为DifferentAffinityActivity创建一个新的Task:

      #7 Task=208 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{82c008a u0 com.test.launchmodetest/.DifferentAffinityActivity t208} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=207 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{cdd2a3e u0 com.test.launchmodetest/.StandardActivity t207} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{9a2658a u0 com.test.launchmodetest/.MainActivity t207} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

Task#208与现有的Task#207的taskAffniity不同,然后在Task#208中我们以FLAG_ACTIVITY_NEW_TASK的方式启动StandardActivity,StandardActivity的taskAffinity与Task#207是一致的:

      #7 Task=207 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{f0d64cb u0 com.test.launchmodetest/.StandardActivity t207} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{cdd2a3e u0 com.test.launchmodetest/.StandardActivity t207} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{9a2658a u0 com.test.launchmodetest/.MainActivity t207} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=208 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{82c008a u0 com.test.launchmodetest/.DifferentAffinityActivity t208} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

这里看到StandardActivity2没有创建到Task#208中,而是创建到了Task#207中,这不同于launchMode为“singleTask”的情况,singleTask的时候如果Task#207中已经存在了正在启动的Activity的一个实例的话,是不会再启动第二个的。

再来对比一下,如果我们在Task#208中启动StandardActivity的时候,没有设置FLAG_ACTIVITY_NEW_TASK,情况如何:

这里看到StandardActivity2无视了taskAffinity的差异,直接创建在了Task#208中。

说明以FLAG_ACTIVITY_NEW_TASK的方式启动Activity的时候,会根据taskAffinity去寻找目标Task。如果没有这个flag,新的Activity直接无脑创建在当前Task中。

1.2.5 在taskAffinity不同的Task中以FLAG_ACTIVITY_NEW_TASK启动Activity(2)

在1.2.4中,看到了,当以FLAG_ACTIVITY_NEW_TASK启动的Activity时,如果启动的Activity的taskAffinity和当前Task(Task#208)的affinity不同,那么这个Activity将会创建在另外一个和该Activity的taskAffinity相同的Task(Task#207)中。

但是我在实际操作中也遇到了一种特殊情况:

先启动一个MainActivity,存在于Task#224。然后以FLAG_ACTIVITY_NEW_TASK启动DifferentAffintyActivty,这个Activity由于taskAffinity与Task#224不同,所以会被创建在Task#225中,接着在Task#225中启动SingleTopActivity,SingleTopActivity虽然taskAffinity与Task#225不同,但是由于启动SingleTopActivity的时候没有声明FLAG_ACTIVITY_NEW_TASK,因此SingleTopActivity会启动在Task#225中。接着将Task#224移动到前台:

      #7 Task=224 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{700b3e2 u0 com.test.launchmodetest/.MainActivity t224} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#5 Task=225 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{7cea9f5 u0 com.test.launchmodetest/.SingleTopActivity t225} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14a0b22 u0 com.test.launchmodetest/.DifferentAffinityActivity t225} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

通过Task#224的MainActivity以FLAG_ACTIVITY_NEW_TASK的方式去启动DifferentAffintyActivty:

        #7 Task=225 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{7cea9f5 u0 com.test.launchmodetest/.SingleTopActivity t225} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{14a0b22 u0 com.test.launchmodetest/.DifferentAffinityActivity t225} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#6 Task=224 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{700b3e2 u0 com.test.launchmodetest/.MainActivity t224} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

这里看到Task#225整个从后台移动到前台,除此之外没有任何改变。

1)、和启动launchMode为singleTask的情况不同,位于StandardActivityz之上的SingleTopActivity并没有被销毁,也就说这次启动只是将StandardActivity所在Task#225移动到前台,在Task#225内部并没有发生Activity的改变。

2)、按照1.2.4的结论,应该是在Task#225中再次创建一个DifferentAffintyActivty的实例,但是事实是Task#225只是从后台移动到了前台,没有任何新实例的创建。至于这一点的原因,跟了一下代码,是因为新启动的DifferentAffintyActivty是Task#225的realActivity,而1.2.4中新启动的StandardActivity却不是Task#207的realActivity,所以1.2.4和1.2.5走了不同的流程,最终DifferentAffintyActivty没有在Task#225中被再次创建,而StandardActivity在Task#207中是被再次创建了。

这里能看到Activity启动的流程要考虑的因素实在太多,只凭taskAffinity、launchMode和Intent flag是无法确定最终情况的。

2 FLAG_ACTIVITY_SINGLE_TOP

2.1 FLAG_ACTIVITY_SINGLE_TOP定义

    /*** If set, the activity will not be launched if it is already running* at the top of the history stack.  See* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html#TaskLaunchModes">* Tasks and Back Stack</a> for more information.*/public static final int FLAG_ACTIVITY_SINGLE_TOP = 0x20000000;

1)、渣翻:

这个flag被设置了的情况下,如果这个Activity已经在当前Task的top运行,那么这个Activity将不会被重新启动。

2)、google文档:

FLAG_ACTIVITY_SINGLE_TOP

如果要启动的 Activity 是当前 Activity(即位于返回堆栈顶部的 Activity),则现有实例会收到对onNewIntent()的调用,而不会创建 Activity 的新实例。
这与 “singleTop” launchMode值产生的行为相同。

2.2 FLAG_ACTIVITY_SINGLE_TOP实际应用

这里每次启动StandardActivity时,都在Intent中添加FLAG_ACTIVITY_SINGLE_TOP,StandardActivity的launchMode声明为standard。

2.2.1 StandardActivity的实例已经处于Task top的情况下尝试启动另一个新实例

以MainActivity为起点,启动StandardActivity:

        #6 Task=125 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3d834ae u0 com.test.launchmode/.StandardActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{a6de54b u0 com.test.launchmode/.MainActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

此时再次以FLAG_ACTIVITY_SINGLE_TOP的方式启动StandardActivity:

由于此时已经有一个StandardActivity的实例位于当前Task的top,因此不会启动一个新的StandardActivity,而是处于Task top的这个StandardActivity实例收到Activity.onNewIntent回调:

03-02 14:30:31.116  1490 31702 I wm_new_intent: [0,64500910,125,com.test.launchmode/.StandardActivity,NULL,NULL,NULL,536870912]
03-02 14:30:31.123  4100  4100 I wm_on_top_resumed_lost_called: [64500910,com.test.launchmode.StandardActivity,pausing]
03-02 14:30:31.125  4100  4100 I wm_on_paused_called: [64500910,com.test.launchmode.StandardActivity,performPause]
03-02 14:30:31.125  4100  4100 I launchmode_test: StandardActivity#onNewIntent
03-02 14:30:31.126  4100  4100 I wm_on_resume_called: [64500910,com.test.launchmode.StandardActivity,LIFECYCLER_RESUME_ACTIVITY]
03-02 14:30:31.127  4100  4100 I wm_on_top_resumed_gained_called: [64500910,com.test.launchmode.StandardActivity,topWhenResuming]

2.2.2 StandardActivity的实例没有处于Task top的情况下尝试启动另一个新实例

接2.2.1,此时再启动一个SingleTopActivity:

        #6 Task=125 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{9bd59d0 u0 com.test.launchmode/.SingleTopActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3d834ae u0 com.test.launchmode/.StandardActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{a6de54b u0 com.test.launchmode/.MainActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

此时StandardActivity不为top,再次尝试启动StandardActivity:

        #6 Task=125 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#3 ActivityRecord{1f5c973 u0 com.test.launchmode/.StandardActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#2 ActivityRecord{9bd59d0 u0 com.test.launchmode/.SingleTopActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{3d834ae u0 com.test.launchmode/.StandardActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{a6de54b u0 com.test.launchmode/.MainActivity t125} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

由于之前启动的StandardActivity的实例StandardActivity1没有位于top,所以这次会创建一个SingleTopActivity的新实例StandardActivity2。

和launchModo设置为“singleTop”的情形相同。

3 FLAG_ACTIVITY_CLEAR_TOP

3.1 FLAG_ACTIVITY_CLEAR_TOP定义

    /*** If set, and the activity being launched 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 will be closed and this Intent* will be delivered to the (now on top) old activity as a new Intent.** <p>For example, consider a task consisting of the activities: A, B, C, D.* If D calls startActivity() with an Intent that resolves to the component* of activity B, then C and D will be finished and B receive the given* Intent, resulting in the stack now being: A, B.** <p>The currently running instance of activity B in the above example will* either receive the new intent you are starting here in its* onNewIntent() method, or be itself finished and restarted with the* new intent.  If it has declared its launch mode to be "multiple" (the* default) and you have not set {@link #FLAG_ACTIVITY_SINGLE_TOP} in* the same intent, then it will be finished and re-created; for all other* launch modes or if {@link #FLAG_ACTIVITY_SINGLE_TOP} is set then this* Intent will be delivered to the current instance's onNewIntent().** <p>This launch mode can also be used to good effect in conjunction with* {@link #FLAG_ACTIVITY_NEW_TASK}: if used to start the root activity* of a task, it will bring any currently running instance of that task* to the foreground, and then clear it to its root state.  This is* especially useful, for example, when launching an activity from the* notification manager.** <p>See* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back* Stack</a> for more information about tasks.*/public static final int FLAG_ACTIVITY_CLEAR_TOP = 0x04000000;

1)、渣翻:
在这个flag设置的情况,如果要启动的Activity已经在当前Task中运行,那么在该Activity上的所有其他Activity将被销毁,并且这个Intent将交付给(现在处于top)旧Activity作为新Intent,而不是启动一个该Activity的新的实例。

举个例子,现在有一个Task包含4个Activity:A,B,C,D。如果D调用startActivity启动B,那么C和D将会被销毁,然后B收到给定的Intent,结果是,现在的Task堆栈情况是:A,B。

在上面的例子中,当前运行的Activity B的实例要么在它的在onNewIntent()方法里接收到你启动的新Intent,要么自己被销毁并且以新的Intent重新启动。如果它已经声明了它的启动模式为“multiple”(默认),而你没有在同一个Intent中设置FLAG_ACTIVITY_SINGLE_TOP,那么它将被销毁并重新创建;对于所有其他的启动模式,或者如果FLAG_ACTIVITY_SINGLE_TOP被设置,那么这个Intent将被发送到当前实例的onNewIntent()。

这个启动模式和FLAG_ACTIVITY_NEW_TASK一起使用也可以达到很好的效果:如果用来启动一个Task的root Activity,它会把Task中运行的实例带到前台,然后清除它到root状态。这特别有用,例如,在从NotificationManager启动Activity时。

2)、google文档:

FLAG_ACTIVITY_CLEAR_TOP

如果要启动的 Activity 已经在当前Task中运行,则不会启动该 Activity 的新实例,而是会销毁位于它之上的所有其他 Activity,并通过onNewIntent() 将此 intent 传送给它的已恢复实例(现在位于堆栈顶部)。

launchMode属性没有可产生此行为的值。

FLAG_ACTIVITY_CLEAR_TOP 最常与 FLAG_ACTIVITY_NEW_TASK 结合使用。将这两个标记结合使用,可以查找其他Task中的现有 Activity,并将其置于能够响应 intent 的位置。

注意:如果指定 Activity 的启动模式为 “standard”,系统也会将其从堆栈中移除,并在它的位置启动一个新实例来处理传入的 intent。这是因为当启动模式为 “standard” 时,始终会为新 intent 创建新的实例。

3.2 FLAG_ACTIVITY_CLEAR_TOP实际应用

这里每次启动测试App的主界面MainActivity时,都在Intent中添加FLAG_ACTIVITY_CLEAR_TOP。

3.2.1 MainActivity的launchMode为standard 的情况

首先在MainActivity界面上启动一个新的StandardActivity:

        #6 Task=128 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{28de46f u0 com.test.launchmode/.StandardActivity t128} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{1ad7ad0 u0 com.test.launchmode/.MainActivity t128} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

然后通过StandardActivity再启动MainActivity,启动的Intent加上FLAG_ACTIVITY_CLEAR_TOP:

        #6 Task=128 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{aceb047 u0 com.test.launchmode/.MainActivity t128} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

之前创建的StandardActivity被销毁,MainActivity的实例MainActivity1被销毁然后重新创建了一个新实例MainActivity2:

03-02 15:17:46.728  1490  5553 I wm_finish_activity: [0,42853487,128,com.test.launchmode/.StandardActivity,clear-task-stack]
03-02 15:17:46.731  1490  5553 I wm_pause_activity: [0,42853487,com.test.launchmode/.StandardActivity,userLeaving=false,finish]
03-02 15:17:46.732  1490  5553 I wm_finish_activity: [0,28146384,128,com.test.launchmode/.MainActivity,clear-task-top]
03-02 15:17:46.733  1490  5553 I wm_destroy_activity: [0,28146384,128,com.test.launchmode/.MainActivity,finish-imm:finishIfPossible]
03-02 15:17:46.743  1490  5553 I wm_task_moved: [128,1,6]
03-02 15:17:46.743  1490  5553 I wm_create_activity: [0,181317703,128,com.test.launchmode/.MainActivity,NULL,NULL,NULL,67108864]
03-02 15:17:46.759  6189  6189 I wm_on_top_resumed_lost_called: [42853487,com.test.launchmode.StandardActivity,topStateChangedWhenResumed]
03-02 15:17:46.763  6189  6189 I wm_on_paused_called: [42853487,com.test.launchmode.StandardActivity,performPause]
03-02 15:17:46.764  1490  5553 I wm_add_to_stopping: [0,42853487,com.test.launchmode/.StandardActivity,completeFinishing]
03-02 15:17:46.770  1490  5553 I wm_restart_activity: [0,181317703,128,com.test.launchmode/.MainActivity]
03-02 15:17:46.772  1490  5553 I wm_set_resumed_activity: [0,com.test.launchmode/.MainActivity,minimalResumeActivityLocked]
03-02 15:17:46.778  6189  6189 I wm_on_destroy_called: [28146384,com.test.launchmode.MainActivity,performDestroy]
03-02 15:17:46.816  6189  6189 I launchmode_test: MainActivity#onCreate
03-02 15:17:46.869  6189  6189 I wm_on_create_called: [181317703,com.test.launchmode.MainActivity,performCreate]
03-02 15:17:46.872  6189  6189 I wm_on_start_called: [181317703,com.test.launchmode.MainActivity,handleStartActivity]
03-02 15:17:46.873  6189  6189 I wm_on_resume_called: [181317703,com.test.launchmode.MainActivity,RESUME_ACTIVITY]
03-02 15:17:46.896  6189  6189 I wm_on_top_resumed_gained_called: [181317703,com.test.launchmode.MainActivity,topStateChangedWhenResumed]
03-02 15:17:47.016  1490  1512 I wm_activity_launch_time: [0,181317703,com.test.launchmode/.MainActivity,294]
03-02 15:17:47.230  1490  1515 I wm_destroy_activity: [0,42853487,128,com.test.launchmode/.StandardActivity,finish-imm:idle]
03-02 15:17:47.349  6189  6189 I wm_on_stop_called: [42853487,com.test.launchmode.StandardActivity,LIFECYCLER_STOP_ACTIVITY]
03-02 15:17:47.353  6189  6189 I wm_on_destroy_called: [42853487,com.test.launchmode.StandardActivity,performDestroy]

3.2.2 MainActivity的launchMode为singleTop 的情况

测试一下MainActivity的launchMode如果不为默认的standard是什么现象,是否和定义中描述的行为一致,即MainActivity是否不会被销毁重建,因此这里设置MainActivity的launchMode为singleTop。

首先在MainActivity界面上启动一个新的StandardActivity:

        #6 Task=130 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#1 ActivityRecord{c383fe3 u0 com.test.launchmode/.StandardActivity t130} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{19f7db4 u0 com.test.launchmode/.MainActivity t130} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

然后通过StandardActivity再启动MainActivity,启动的Intent加上FLAG_ACTIVITY_CLEAR_TOP:

        #6 Task=130 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]#0 ActivityRecord{19f7db4 u0 com.test.launchmode/.MainActivity t130} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1920,1200]

之前创建的StandardActivity被销毁,MainActivity没有销毁,收到Activity.onNewIntent的回调:

03-02 15:24:34.710  1490  9314 I wm_finish_activity: [0,205012963,130,com.test.launchmode/.StandardActivity,clear-task-stack]
03-02 15:24:34.712  1490  9314 I wm_pause_activity: [0,205012963,com.test.launchmode/.StandardActivity,userLeaving=false,finish]
03-02 15:24:34.714  1490  9314 I wm_new_intent: [0,27229620,130,com.test.launchmode/.MainActivity,android.intent.action.MAIN,NULL,NULL,270532608]
03-02 15:24:34.715  1490  9314 I wm_task_moved: [130,1,6]
03-02 15:24:34.727  6902  6902 I wm_on_top_resumed_lost_called: [205012963,com.test.launchmode.StandardActivity,topStateChangedWhenResumed]
03-02 15:24:34.728  6902  6902 I wm_on_paused_called: [205012963,com.test.launchmode.StandardActivity,performPause]
03-02 15:24:34.729  1490  9314 I wm_add_to_stopping: [0,205012963,com.test.launchmode/.StandardActivity,completeFinishing]
03-02 15:24:34.734  1490  9314 I wm_set_resumed_activity: [0,com.test.launchmode/.MainActivity,resumeTopActivityInnerLocked]
03-02 15:24:34.743  1490  9314 I wm_resume_activity: [0,27229620,130,com.test.launchmode/.MainActivity]
03-02 15:24:34.786  6902  6902 I wm_on_restart_called: [27229620,com.test.launchmode.MainActivity,performRestartActivity]
03-02 15:24:34.786  6902  6902 I wm_on_start_called: [27229620,com.test.launchmode.MainActivity,handleStartActivity]
03-02 15:24:34.787  6902  6902 I launchmode_test: MainActivity#onNewIntent
03-02 15:24:34.787  6902  6902 I wm_on_resume_called: [27229620,com.test.launchmode.MainActivity,RESUME_ACTIVITY]
03-02 15:24:34.788  6902  6902 I wm_on_top_resumed_gained_called: [27229620,com.test.launchmode.MainActivity,topWhenResuming]
03-02 15:24:35.227  1490  1515 I wm_destroy_activity: [0,205012963,130,com.test.launchmode/.StandardActivity,finish-imm:idle]
03-02 15:24:35.248  6902  6902 I wm_on_stop_called: [205012963,com.test.launchmode.StandardActivity,LIFECYCLER_STOP_ACTIVITY]
03-02 15:24:35.249  6902  6902 I wm_on_destroy_called: [205012963,com.test.launchmode.StandardActivity,performDestroy]

四、总结

1 launchMode

1.1 standard

每次启动Activity都会在当前Task中创建一个Activity的新的实例。

1.2 singleTop

1)、如果要启动的Activity已经有一个对应的实例处于当前Task的top,那么不会创建一个新实例。

2)、如果当前Task中运行了该Activity的一个实例,但是没有位于Task的top,那么创建一个新实例。

1.3 singleTask

1.3.1 要启动的Activity的taskAffinity和当前Task的affinity(默认为App包名)相同

1)、如果要启动的Activity已经位于Task的top,不会创建新的实例。

2)、如果当前Task中运行了该Activity的一个实例,但是没有位于Task的top,那么清除掉该Activity之上的所有Activity。

1.3.2 要启动的Activity的taskAffinity和当前Task的affinity(默认为App包名)不同

1)、如果当前Task中没有运行这个Activity的一个实例,那么在为这个Activity创建一个新的Task。

2)、如果后台Task中有某个Task正在运行这个Activity,那么不会创建新的实例,而是将该Task移动到前台,并且,移除掉该Task中位于这个Activity之上的所有Activity。

1.4 singleInstance

如果有任何Task正在运行这个Activity,将该Task移动到前台,否则总是为这个新启动的Activity创建新的Task,并且这个Task中只能有这一个Activity。

1.5 SingleInstancePerTask

默认作用和singleTask相似,不同的在于singleInstancePerTask不需要设置一个不同的taskAffinity即可创建新的Task。

另外结合Intent.FLAG_ACTIVITY_MULTIPLE_TASK和Intent.FLAG_ACTIVITY_NEW_DOCUMENT,每次启动了launchMode设置为“singleInstancePerTask”的Activity都可以创建一个新的Task,那么这个新启动的Activity自然就是这个新创建的Task的root Activity。

1.6 再次总结

说的白话一点,standard、singleTop、singleTask和singleinstance这4种启动模式对Activity的实例数量要求是逐渐升级的:

standard:可以创建无数个Activity实例。

singleTop:如果当前Task的top如果已经是正在启动的这个Activity,那就不要重复启动。

singleTask:这个Activity只能有一个,且作为它所在的Task的root Activity(对于taskAffinity不同的情况)。

singleInstance:这个Activity只能有一个,且它所在的Task也只能有它这一个Activity。

singleInstancePerTask:是singleTask的扩展,这个Activity可以有多个实例,但是每个都是所在的Task的root Activity。

2 Intent flag

2.1 FLAG_ACTIVITY_NEW_TASK

如果有FLAG_ACTIVITY_NEW_TASK的参与,那么在启动Activity的时候就要把taskAffinity这一因素考虑进去,这会影响到该Activity是启动在当前Task中,还是新的Task中。根据之前的分析,这个flag的作用和launchMode为“singleTask”其实是不同的,比较复杂。

2.2 FLAG_ACTIVITY_SINGLE_TOP

作用和launchMode为“singleTop”相同。

2.3 FLAG_ACTIVITY_CLEAR_TOP

如果当前Task中正在运行这个Activity,那么清除这个Activity之上的所有其他Activity。

根据正在启动的这个Activity的launchMode,以及启动的Intent的flag,这个现有Activity可能也会被销毁重建。

【Android 12】Activity启动模式相关推荐

  1. Android中Activity启动模式

    Android中Activity启动模式一共是四种,这里我写一下我对其的理解: 1.standard(默认) 2.singleTop,如果某个Activity设置了该属性,且当前Activity就是这 ...

  2. Android利用activity启动模式退出整个应用

    Android利用activity启动模式退出整个应用 作者:翔星幻羽发布于:02月22日 13:39访问(22)评论(0) Android利用activity启动模式退出整个应用 分类: andro ...

  3. Android中Activity启动模式详解

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  4. Android初级开发笔记-- activity启动模式的学习(1)

    第一次学习Android中一个很重要的概念,启动模式.文章记录的也只是一些入门知识,随着学习的深入还会有activity启动模式的学习(2)和(3). 下面分三个小点说一下对启动模式的理解区别以及如何 ...

  5. Android activity启动模式

    如何正确理解和使用 Activity的4种启动模式 关于Activity启动模式的文章已经很多,但有的文章写得过于简单,有的则过于注重细节,本文想取一个折中,只关注最重要和最常用的概念,原理和使用方法 ...

  6. Android系统(187)---最易懂的Activity启动模式详解

    Android基础:最易懂的Activity启动模式详解 前言 Android基础中,Activity的启动模式非常重要 本文将全面介绍 Activity的启动模式 目录 目录 1. 定义 即Acti ...

  7. Android Activity 启动模式详解

    最近有群里的朋友问我 Activity的四种启动模式分别是什么意思? 当初因为项目比较忙,草草的解释了下, Api文档中说的也只是一般,在这里就小记一下吧,以便有更多的朋友对Activity启动模式了 ...

  8. Android开发面试题之Activity启动模式讲解总结

    activity启动模式分为: Standard :默认的启动模式每次启动activity都会新建一个activity,不管是否此activity是否存在 SingleTop :栈顶复用模式,每次启动 ...

  9. (二)Activity启动模式

    启动模式 一.概念 顾名思义,就是activity的启动方式方法,共有4种模式standard,singleTop,singleTask,singleInstance. 为什么要学习启动模式呢?因为有 ...

  10. And解roid中Activity启动模式详

    转自: http://www.cnblogs.com/fanchangfa/archive/2012/08/25/2657012.html And解roid中Activity启动模式详 在Androi ...

最新文章

  1. 二叉树的层次遍历 II
  2. 搭建hue遇到的错误 Couldn't find log associated with operation handle: OperationHandle
  3. 第04章—整合Mybatis
  4. JavaScript精简代码 非一般的写法(转载)
  5. C++Primer 第一章 快速入门 学习
  6. 关于Oracle10g归档参数的研究
  7. GPS经纬度转百度经纬度JAVA
  8. 计算机cd立体太极图,太极图是三维立体的
  9. 【C++】平方矩阵求解
  10. 通过简单的C语言解决找钱问题
  11. gt、lt、ge、le、eq、ne的含义
  12. 【DASCTF2023】Misc mp3
  13. EGE图形库 vs配置错误解决
  14. matlab如何导入大量的图片_本期介绍:如何在论文中插入高清的图片
  15. 程序员该如何把 Windows 系统打造的跟 Mac 一样牛逼?
  16. 机器学习- MACHINE LEARNING
  17. 【loadrunner】——利用loadrunner进行压力测试
  18. 【韩松】Deep Gradient Comression_一只神秘的大金毛_新浪博客
  19. spotify使用教程_如何在iPhone上的Siri中使用Spotify
  20. 最全前端面试问题及答案总结(转载自hawx1993)

热门文章

  1. 星起航:维护好私域流量池要有哪些要素?
  2. Python类实例化时出现 take no arguements 的错误
  3. 2021华东师范大学计算机专硕考研经验贴
  4. 买卖双方的尼日利亚进出口海关数据 贸易动力
  5. 计算机重启后屏幕就剩一个J,电脑重启后老是显示黑屏怎么办
  6. 非线性光纤光学中分步傅里叶算法(SSFFT)的matlab代码实现
  7. OGC标准WMTS服务概念与地图商的瓦片编号流派-web地图切片加载
  8. Python基础047:Pycharm debug时设置断点但是不起作用怎么回事?
  9. 需要证件照怎么办?教你如何自己在线做照片
  10. 12V将路由器网口烧了