Activity 的 launch Mode 梳理
前置概念
-
Task
每个App启动之后,在最近任务列表中就可以查看到启动的App,这里看到的其实是Task列表,看到的是一个个App的Task。
Task栈由启动的Activity组成。每个Activity启动都要和一个Task相关。
-
TaskAffinity
任务相关性,每个Activity都有自己的TaskAffinity,默认是Application的TaskAffinity,而Application的TaskAffinity默认是App的包名。
它相当于为Activity做了分组。每个Task中的的TaskAffinity都是相同的,即启动的第一个Activity的TaskAffinity。TaskAffinity可以自定义,如果一个Activity指定了和Application不同的TaskAffinity,并且启动模式是SingleTask或SingleInstance,那么它在App内被启动的时候就会跑到这个TaskAffinity的Task中,如果没有找到这个Task,就会新建。
其他知识
-
allowTaskReparenting
Activity可以在Manifest指定这个属性,默认为false。当它为true时,允许Activity被挪到启动它的Task中,然后再点击这个Activity所属的App时,这个Activity又会回到这个Task中,而启动它的Task中的Activity消失了。
-
任务切换
当启动的Activity不属于启动Task的时候,即TaskAffinity不一样,则会发生任务切换,会有任务切换的动画,这是系统提醒用户,是在做跨任务操作。
Launch Mode 的四种类型
-
Standard 默认类型
Activity不指定Launch Mode 时就是这个模式。不管是否有这个Activity的实例,启动就会新建,并且加入启动它的Task栈中。
-
SingleTop栈顶复用模式
如果这个Activity在Task栈顶,则再启动不会新建实例,直接复用这个栈顶的Activity,如果不是在栈顶,则会新建,加入启动它的Task栈中。
-
SingleTask栈内复用模式
如果这个Activity在启动它的Task栈内,则再启动不会新建实例,直接复用这个栈内的Activity,并且会让在它之上的Activity出栈,即有一个Clear Top 的效果。如果启动Task栈中没有这个Activity实例,则会新建Activity,如果这个Activity的TaskAffinity和启动Task栈的TaskAffinity不一致,则会新建Task,将这个Activity加入到栈顶。这个模式的Activity的一个特殊的特性是它会跟随它的TaskAffinity的Task,而不是启动它的Task。 例如:App1 :A ->B App2:A2->B2-C2,B2是SingleTask的启动模式,其他的都是默认模式。这时App1启动App2的B2 Activity,这个时候B2不会跑到App1的Task中,还会在App2的Task中,App2因为栈中有这个Activity的实例,所以会直接复用,并且会清掉它上方的Activity,这时App2:A2->B2;接着这个Task会被重叠到App1的Task之上,组成了回退栈:A->B->A2->B2。
-
SingleInstance 单实例模式
比SingleTask特性更强,只允许存在一个Task中,并且这个Task只允许有这个一个Activity。也就是说即使没有特殊指定TaskAffinity的SingleInstance的Activity,在第一次启动的时候,也会为它单独创建一个Task,把它装进去,之后再启动它时,直接复用这个Activity,这个Activity的Task会被重叠到启动它的Task的上面。这个Activity的TaskAffinity是跟它Application是相同的,也就是说会存在两个TaskAffinity相同的Task,而两个重叠的Task在点击最近任务按键或切换到后台时,会被拆开。但是最近任务列表中只会出现每个App的一个Task,也就是说调起最近任务查看Task,会发现这个SingleInstance的Task不见了,找不到这个Activity了,虽然看不见,但它依然存在。
适用场景
启动模式 | 适用场景 |
---|---|
Standard | App内使用,普通的Activity,用完即finish。跨App使用,逻辑独立的Activity,启动之后跟所属App没有关系了。 |
SingleTop | 使用场景和Standard类似,加了一个栈顶就不会重建的特性。 |
SingleTask | App内使用,一般是MainActivity,栈内复用,保证只有一个Activity实例,由于Clear Top的属性,可以用来优雅退出应用(finish掉它上方所以的Activity)。跨App使用,用来提供外部App使用的Activity启动时的特性,会将这个Activity所属的Task都叠加到启动它的Task之上,组成回退栈。例如:App1启动App2的SingleTask的Activity,按返回键回退时,先回退App2的栈,然后App2的Activity都出栈之后,App1的Activity才出栈。一般用于那种提供给外部App启动的,并且逻辑依赖自身App的Activity,因此在切换到这个Activity所属的App时,这个Activity依然存在。 |
SingleInstance | 一般用于跨App使用,提供给外部App启动Activity,逻辑独立的Activity,会提供独立的Task承载这个Activity。外部App处理完之后,返回,因为这个Task只有一个Activity,所以就直接返回到启动它的Task了,不会将你不想见到的Activity加到这个Task中,从而你的回退栈出现多余的Activity。 |
其他 | |
allowTaskReparenting | 一般适用于可以给外部App启动的Activity,会到外部AppTask栈中,但不会将它原先所属的Task的Activity整个搬过去加到回退栈中。并且再打开它原先的App时,这个Activity还会回来原先的Task。适用于可以提供给外部启动的Activity,并且这个Activity依赖原先App的逻辑,再切回原先App这个Activity依然会回来,并且不会打乱启动它的App的回退逻辑。 |
总结
Activity的启动模式不算难,理解了Task和TaskAffinity的概念再理解SingleTask和SingleInstance的启动模式时就很容易理解了。每个App启动的Activity被分组并抽象成了Task栈,这个分组是TaskAffinity决定的。启动SingleTask和SingleInstance时,如果Activity的TaskAffinity和启动它的Task不相同的话,就会发生跨任务操作,首先会去找这个Activity所属的Task是否存在,如果不存在就会新建Task。这些启动模式的特性决定了需要根据需求去实现怎样的Activity启动和切换,是Task内切换还是跨Task切换,是将另一个Task的Activity叠加到回退栈中,还是只需要这一个外部Activity在回退栈中等等。
转载自:https://juejin.cn/post/6890348438485368839