本文结合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 Back
Stack</a> document for important information on how these options impact
the behavior of your application.
<p>If this attribute is not specified, <code>standard</code> launch
mode will be used. Note that the particular launch behavior can
be 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 of
the activity when it is started, though this behavior may change
with the introduction of other options such as
{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
Intent.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 an
instance of the same activity class in the foreground that is
interacting with the user, then
re-use that instance. This existing instance will receive a call to
{@link android.app.Activity#onNewIntent Activity.onNewIntent()} with
the 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 running
that starts with this activity, then instead of starting a new
instance the current task is brought to the front. The existing
instance will receive a call to {@link android.app.Activity#onNewIntent
Activity.onNewIntent()}
with the new Intent that is being started, and with the
{@link android.content.Intent#FLAG_ACTIVITY_BROUGHT_TO_FRONT
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT} flag set. This is a superset
of the singleTop mode, where if there is already an instance
of the activity being started at the top of the stack, it will
receive the Intent as described there (without the
FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set). See the
<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
Stack</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 all
activities in the application), or with the activity tag (to supply
a specific affinity for that component).
<p>The default value for this attribute is the same as the package
name, indicating that all activities in the manifest should generally
be considered a single "application" to the user. You can use this
attribute to modify that behavior: either giving them an affinity
for another task, if the activities are intended to be part of that
task from the user's perspective, or using an empty string for
activities 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 be
running. This activity gets a unique task with only itself running
in it; if it is ever launched again with the same Intent, then that
task will be brought forward and its
{@link android.app.Activity#onNewIntent Activity.onNewIntent()}
method called. If this
activity tries to start a new activity, that new activity will be
launched in a separate task. See the
<a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
Stack</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 activity
that created the task, and therefore there will only be one instance of this activity
in a task. In constrast to the {@code singleTask} launch mode, this activity can be
started 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可能也会被销毁重建。