singleTask 与 taskAffinity 缠绵的那些事

这里说的也适用于其它Activity启动时Intent中设置了FLAG_ACTIVITY_NEW_TASK标志。


今天没事翻看android sdk的文档,发现在网上关于launchMode的一些介绍,很多都不是太正确,尤其是关于singleTask,甚至官方文档的介绍都有些问题,自己也写了小demo做了测试,把对singleTask的理解做下总结,如有错误,欢迎拍砖交流。


首先,singleTask不能独立来评价。我在网上看过几篇对launchMode介绍的比较好的几篇文章(http://marshal.easymorse.com/archives/2950,http://blog.csdn.net/liuhe688/article/details/6754323 ),因为只是独立的介绍singleTask, 看过之后再看到官方文档中的“The system creates a new task and instantiates the activity at the root of the new task”不免让人疑惑。
要理解官方文档中这句容易引起歧义的句子,必须要先了解下taskAffinity,下面是关于taskAffinity的介绍。


每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。 


taskAffinity的值是个唯一的String字符串,来自于manifest文件中声明的包名。


官方文档中说了如果一个singleTask的Activity没有已存在的实例,就会新建一个task来存这个activity的实例,而写程序测试的例子是标准的ActivityA启动singleTask的ActivityB,你会发现他们的TaskId是一样的,也就是说创建ActivityB后,并没有把它放到新的task中。如果结合affinity介绍,就好理解一些了:


App1(com.df.test1): ActivityA -> ActivityB -> ActivityC -> ActivityB
App2(com.df.test2): Activity1 -> ActivityB(调用App1中的ActivityB)


1、假设ActivityB设置了launchMode为"singleTask", taskAffinity没有设置(即为包名),(1.1)在App1中它被启动ActivityB时,先去查找有没有与它的taskAffinity匹配的task存在,因为ActivityA与ActivityB的taskAffinity相同,所以会在当前的task中启动ActivityB,此时再启动ActivityC,然后再启动ActivityB,按“Back",会发现回到了ActivityA,即ActivityC启动ActivityB时,在栈中查到了AcvitityB,让它上面的都出栈并激活ActivityB,它们打印出的taskId都一样,这个跟上面两篇文章介绍的一致。



(1.2)在App2中启动ActivityB时:
如果App1没有在后台运行,此时查找与ActivityB的taskAffinity相同的task,发现不存在,会新建一个task启动ActivityB,此时你会发现它们的taskId值不一样;
如果App1在后台运行,系统查找到与ActivityB相同taskAffinity的task,会在这个task中启动(如果App1中栈顶为ActivityC,它会被出栈并激活ActivityB, 如果栈顶为ActivityA,会新建ActivityB),此时,进入顺序为Activity1->ActivityB Back顺序为ActivityB->ActivityA->Activity1.


 (1.3)如果App2在后台运行,栈顶为ActivityB,运行App1,你会发现App1直接进入了ActivityB,按Back,直接退出,再激活App2,发现当前界面为Activity1,这个看起来就有些奇怪。


2、假设ActivityB设置了launchMode为"singleTask",taskAffinity设置为com.df.test2(与App2相同) 

(2.1)在App1中启动ActivityB时,如果App2没有在后台运行,此时系统查找不到与ActivityB的taskAffinity相同的task,会创建新的task并在其中启动ActivityB,此时,会发现ActivityB的taskId与ActivityA不一样,但与ActivityC的taskId是一样的,因为是它启动的ActivityC,而ActivityC的launchMode又为默认的,此时它的taskAffinity跟task中的Root Activity相同。

如果App2已经在后台运行,系统查找到与ActivityB相同的task,如果ActivityB已在这个task中,直接激活,如果没有,就在这个task中启动ActivityB. 此时,进入顺序:ActivityA -> AcitivytB  back顺序:ActivityB->Activity1->ActivityA


(2.2)在App2中启动ActivityB,会发现它的taskId与Activity1是一样的。


(2.3)如果App1已在后台运行,而且ActivityB已经在栈中,此时运行App2,发现会直接进行ActivitB或ActivityC,在ActivityB界面按Back,直接退出App2.

你可能感兴趣的:(Android开发)