Activity启动模式二

简书上图片抓取总是失败,可以到这里Activity启动模式二
阅读,谢谢!


上篇文章Activity启动模式一主要介绍了Activity的四种启动模式,这些启动模式都是在AndroidManifest中进行配置的。除此之外,Android系统还通过Intent类提供了一些标志位,同样可以指定Activity的启动模式。本文将介绍下这些和Activity启动相关的标志位。

一般情况下,我们在启动目标Activity的Intent中指定这些标志位,如下所示:

Intent intent = new Intent();
intent.setClass(MainActivity.this,FirstActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

当同时在配置文件中指定launchMode和在Intent中指定上面的标志位时,以标志位为准,即代码的优先级比AndroidManifest的优先级更高!

下面我们通过具体案例看下和Activity启动相关的4种标志位:

Activity启动相关的四种标志位

FLAG_ACTIVITY_NEW_TASK

官方文档上介绍该标志位和SingleTask启动模式具有相同效果,其实不然。应该是FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP一起等同于SingleTask启动模式。

这里我们通过4个案例,看下单独使用FLAG_ACTIVITY_NEW_TASK标志位和一起使用FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TOP标志位的具体效果。

案例1

两个Activity的taskAffinity属性相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,TaskAffinity也相同。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-ab0b5-1571789169660)]
可见,因为两个Activity的taskAffinity属性相同,所以第一次启动FirstActivity时并没有创建新的任务栈。

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-171689-1571789169660)]
因为只有FLAG_ACTIVITY_NEW_TASK标志位,没有FLAG_ACTIVITY_CLEAR_TOP,所以无法清除FirstActivity之上的MainActivity,复用已有FirstActivity。而是创建了新的FirstActivity。

通过上面的任务栈可知:在taskAffinity相同的情况下,单独添加FLAG_ACTIVITY_NEW_TASK不起任何作用。

案例2

两个Activity的taskAffinity属性不相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,但是TaskAffinity不同。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:

new_task-taskAffinity不同-1

可见,因为两个Activity的taskAffinity属性不同,所以第一次启动FirstActivity时,创建了新的任务栈(TaskId为1979).

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-86c3a2-1571789169660)]
可以看到,任务栈没有发生任何变化,也没有创建新的FirstActivity实例。这是因为FirstActivity实例已经存在于它所期望的任务栈中,而单独添加FLAG_ACTIVITY_NEW_TASK标志位又不会清除任务栈中位于FirstActivity之上的Activity实例,所以就没有发生跳转。

通过上面的任务栈可知:在taskAffinity不同的情况下,第一次启动FirstActivity时,会新建一个任务栈,并将FirstActivity实例添加到该task中。这与SingleTask启动模式产生的效果是一致的。但是,当企图再次从MainActivity进入到FirstActivity时,却什么也没有发生,原因上面已经说明了。

综上所述,单独使用FLAG_ACTIVITY_NEW_TASK会产生非常奇怪的行为,因此一般和FLAG_ACTIVITY_CLEAR_TOP标志位一起使用,这样可以实现类似SingleTask的效果,但是不完全相同,下面会进行介绍。

下面我们再通过两个案例看下FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP一起使用的效果。

案例3

两个Activity的taskAffinity属性相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,TaskAffinity也相同。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP标志位,启动MainActivity的Intent不包含任何标志位.

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-719efa-1571789169660)]
可见,因为两个Activity的taskAffinity属性相同,所以第一次启动FirstActivity时并没有创建新的任务栈。

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-bd3fd8-1571789169660)]
貌似是和SingTask启动模式的效果相同,但是细看一下就会发现区别:前后两次FirstActivity实例是不同的,也就是没有复用第一次启动的FirstActivity,而是清除了FirstActivity及其之上的所有Activity,然后新建FirstActivity实例添加到了当前任务栈

通过上面的任务栈可知:在taskAffinity相同的情况下,FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP标志位组合确实不会创建新的任务栈,但是会清除了FirstActivity及其之上的所有Activity,并新建FirstActivity实例添加到了当前任务栈,这点是和SingleTask模式的差异。(SingleTask仅会清除FirstActivity之上的Activity,然后复用已有的FirstActivity)

案例4

两个Activity的taskAffinity属性不相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,但是TaskAffinity不同。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-5bff63-1571789169660)]
可见,因为两个Activity的taskAffinity属性不同,所以第一次启动FirstActivity时,创建了新的任务栈(TaskId为1980).

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-5cab4b-1571789169660)]
可以看到,和案例3 taskAffinity属性相同的情况类似(除了创建了新的任务栈),直接清除了FirstActivity及其之上的所有Activity,然后创建新的FirstActivity实例添加到新的任务栈(TaskId为1980)。

通过上面的任务栈可知:在taskAffinity不同的情况下,FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP标志位组合会为首次启动的FirstActivity创建新的任务栈,其他的逻辑与案例3基本相同,都是直接清除了FirstActivity及其之上的所有Activity,然后创建新的FirstActivity实例,这也是和SingleTask模式的区别

综上所述,FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP标志位组合产生的效果总体上和SingleTask模式相同,除了不会复用FirstActivity实例之外。

FLAG_ACTIVITY_CLEAR_TOP

该标志位在上面已经使用过了,作用是清除包含目标Activity的任务栈中位于该Activity实例之上的其他Activity实例。但是是复用已有的目标Activity,还是像上面那样先删除后重建,则有以下规则:

  1. 若是单独使用FLAG_ACTIVITY_CLEAR_TOP,那么只有非Standard启动模式的目标Activity才会被复用,其他启动模式的目标Activity都先被删除,然后被重新创建并入栈。
  2. 若是使用FLAG_ACTIVITY_SINGLE_TOP和FLAG_ACTIVITY_CLEAR_TOP标志位组合,那么不管目标Activity是什么启动模式,都会被复用。

因为上面的案例3和案例4都不符合上面的两条规则,所以FirstActivity才会先被清除,然后重建。

下面我们通过几个具体案例,验证下上面的两条规则:

案例1

具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_CLEAR_TOP标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-f2049f-1571789169660)]

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-d6a89a-1571789169660)]

通过上面的任务栈可知:第二次MainActivity -> FirstActivity时,会先把FirstActivity以及之上的Activity全部销毁,然后创建新的FirstActivity入栈,正符合我们的预期。

案例2

具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,MainActivity的启动模式是Standard,FirstActivity的启动模式是SingleTop。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_CLEAR_TOP标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-929577-1571789169660)]

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-ae0831-1571789169660)]

通过上面的任务栈可知:第二次MainActivity -> FirstActivity时,会先把FirstActivity之上的Activity全部销毁,然后复用已有的FirstActivity实例,也符合我们的预期。


此外,当FirstActivity是SingleTask和SingleInstance模式时,其效果和SingleTop启动模式一样,也是首先销毁FirstActivity之上的所有Activity,然后复用已有的FirstActivity实例。

这里仅给出我验证的任务栈:
当FirstActivity是SingleTask模式时(taskAffinity相同),经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:

clear_top-SingleTask-1

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-2033ce-1571789169660)]
可见,确实复用了已有的FirstActivity实例。

当FirstActivity是SingleInstance模式时,经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:

clear_top-SingleInstance-1

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-b9bbdc-1571789169660)]
可见,确实复用了已有的FirstActivity实例。

综上所述,通过案例1和案例2,我们验证了规则1是OK的。
下面我们继续验证下规则2:

案例3

具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard。
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_SINGLE_TOP + FLAG_ACTIVITY_CLEAR_TOP标志位,启动MainActivity的Intent不包含任何标志位。

经过MainActivity -> FirstActivity -> MainActivity后,最终的任务栈如下所示:
[图片上传失败...(image-1755e0-1571789169660)]

最后,MainActivity再次启动FirstActivity后,最终的任务栈如下所示:
[图片上传失败...(image-b839b2-1571789169660)]

通过上面的任务栈可知:第二次MainActivity -> FirstActivity时,会先把FirstActivity之上的Activity全部销毁,然后复用已有的FirstActivity实例,也符合我们的预期。

综上所述,既然在FLAG_ACTIVITY_SINGLE_TOP + FLAG_ACTIVITY_CLEAR_TOP标志位组合的情况下,Standard模式的FirstActivity都已经被复用了,那么其他启动模式的Activity也必然会被复用。(单独使用FLAG_ACTIVITY_CLEAR_TOP都会被复用,何况又添加了FLAG_ACTIVITY_SINGLE_TOP标志位,通过Demo验证也确实如此,就不再给出具体案例了)。

综上所述,上面的两条规则还要是遵守的_

FLAG_ACTIVITY_CLEAR_TASK

该标志位一般和FLAG_ACTIVITY_CLEAR_TASK一起使用,目的是启动目标Activity时,首先清空已经存在的目标Activity实例所在的任务栈,这自然也就清除了之前存在的目标Activity实例,然后创建新的目标Activity实例并入栈。

经过Demo测试发现,单独使用FLAG_ACTIVITY_CLEAR_TASK标志位,不管taskAffinity是否相同,都不会产生什么效果。例如下面是单独使用该标志位的最终任务栈(taskAffinity相同 or 不同都是这样):
[图片上传失败...(image-da08ca-1571789169660)]
感兴趣的可以自行尝试,这里不再赘述。

下面看下FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位组合在taskAffinity相同 and 不同的情况下的效果。

案例1

两个Activity的taskAffinity属性相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,taskAffinity也相同
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位,启动MainActivity的Intent不包含任何标志位。

第一次启动MainActivity后,任务栈如下所示:
[图片上传失败...(image-eea7c-1571789169660)]

接着MainActivity启动FirstActivity后,任务栈如下所示:
[图片上传失败...(image-12b579-1571789169660)]
首先启动的MainActivity居然被清除了,然后才创建了FirstActivity实例。

然后FirstActivity启动MainActivity后,任务栈如下所示:
[图片上传失败...(image-834c6b-1571789169660)]

最后MainActivity再次启动FirstActivity后,任务栈如下所示:
[图片上传失败...(image-d1d89-1571789169660)]
可见,系统再次清除了FirstActivity及其之上的MainActivity,然后重新创建了新的FirstActivity实例并入栈。

通过上面的任务栈可知:当通过FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位组合启动FirstActivity时,首先会清空FirstActivity所在的任务栈,然后再创建新的FirstActivity实例并入栈

案例2

两个Activity的taskAffinity属性不相同,具体步骤如下所示:

  1. 创建MainActivity和FirstActivity,且两者的启动模式都是Standard,taskAffinity不相同
  2. 首先启动MainActivity,接着通过MainActivity启动FirstActivity,然后再通过FirstActivity启动MainActivity,如此反复。
  3. 启动FirstActivity的Intent中指定了FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位,启动MainActivity的Intent不包含任何标志位。

第一次MainActivity启动FirstActivity后,任务栈如下所示:
[图片上传失败...(image-8f36ac-1571789169660)]
因为taskAffinity不同,所以为FirstActivity实例创建了新的任务栈。

然后FirstActivity启动MainActivity后,任务栈如下所示:
[图片上传失败...(image-2878f1-1571789169660)]

最后MainActivity再次启动FirstActivity后,任务栈如下所示:
[图片上传失败...(image-d44223-1571789169660)]
可见,系统首先清除了任务栈(TaskId为2040)中FirstActivity及其之上的MainActivity,然后重新创建了新的FirstActivity实例并入栈(TaskId为2040)。

通过上面的任务栈可知:当通过FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位组合启动FirstActivity时,首先会清空FirstActivity所在的任务栈,然后再创建新的FirstActivity实例并入栈,这和taskAffinity属性相同是一致的效果,只不过这里第一次为FirstActivity创建了新的任务栈

综上所述,当通过FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TASK标志位组合启动目标Activity时,首先会清空目标Activity所在的任务栈(若目标Activity是第一次启动,那么会清空目标Activity所期望的任务栈),然后创建新的目标Activity实例并入栈。

FLAG_ACTIVITY_SINGLE_TOP

该标志单独使用就可以达到SingleTop启动模式的效果,该类效果可以参考前篇文章,这里不再赘述。

Activity启动相关的属性

这里简单介绍一些AndroidManifest配置文件中与启动模式相关的属性。其实前一篇文章已经介绍了两个比较常用的属性:android:taskAffinityandroid:allowTaskReparenting,下面再补充一些不常用的属性。

android:clearTaskOnLaunch

字面意思是:是否在启动时清除任务栈,该属性默认为false,表示是否在APP启动时,清除任务栈中除根Activity之外的其他Activity实例。该属性只对任务栈内的根Activity起作用,任务栈内其他的Activity都会被忽略。

比如:我们有一个App,依次启动了ActivityA、ActivityB和ActivityC,其中ActivityA和ActivityB都设置clearTaskOnLaunch属性为true。那么首先点击“Home”建回到Launcher界面,然后再启动该App,我们看到是ActivityA界面,而ActivityB和ActivityC都被销毁了。
除非栈底的ActivityA已经被销毁,那么上面设置clearTaskOnLaunch属性为true的activity(B)才会生效。

android:finishOnTaskLaunch

该属性默认值为false,表示当离开当前Activity所在的任务栈时,立即销毁当前Activity,而其他Activity不受影响。

android:alwaysRetainTaskState

该属性默认值为false,表示App的任务栈是否保持原来的状态。该属性只对task的根Activity起作用,其他的Activity都会被忽略。 默认情况下,若一个App在后台停留的时间太长,那么再启动该App时,系统会清除任务栈中除了根Activity之外的其他Activity,但是如果根Activity设置了该属性,那么再次启动应用时,就不会清除Task中的Activity,而是保持原样,因此仍然可以看到上一次操作的界面。


OK,Activity启动模式相关的内容就介绍这些吧,希望对自己对感兴趣的同学都有所帮助_

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容