Android进阶之路--启动模式

来源:互联网 发布:minecraft0.15js 编辑:程序博客网 时间:2024/06/06 12:22

Android的启动模式是个难点,因为形形色色的启动模式实在是太容易混淆了,但是在项目开发中确十分重要,比如一个APP接收到一条push,点击push打开对应的activity,为了关闭push详情后还继续留在app内,这时候启动模式就会起到作用。启动模式在面试当中也基本是必问的一个问题,所以我们必须搞清楚每个启动模式的作用和原理。

 Activity有四种启动模式:standard 、singleTop 、singleTask、singleInstance

 

Standard: 标准模式,也是系统的默认模式。每次启动一个activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的新的实例执行activity所需的所有生命周期,新的实例运行在创建它的 activity所在的栈中。

注意:当我们用Application去启动standard模式的activity时会报错,这是因为非activity类型的context没有所谓的任务栈,解决这个问题方法是为待启动的activity指定FLAG_ACTIVITY_NEW_TASK 标记位,这样在启动的时候为该activity创建了一个新的任务栈,这个时候待启动的activity实际上是以singleTask 模式启动的,后面讲下singleTask模式就明白了。

举例:假设目前栈内是ABCD,A位于栈底,D位于栈顶,这时候再次启动D,   且D的启动模式是Standard,那么栈内情况是ABCDD;

 

 SingleTop : 栈顶复用模式。这种模式下,如果待启动的activity已经存在并位于任务栈的栈顶,那么此activity不会重新创建,同时它的onNewIntent 方法会被回调,通过该方法的参数我们可以取出当前请求的信息。

注意:新启动的activity不会执行onCreate、onStart方法,如果新启动的activity没有位于栈顶,那么新的activity仍会重新创建。

举例:假设目前栈内是ABCD,A位于栈底,D位于栈顶,这时候再次启动D,   且D的启动模式是singleTop,那么栈内情况仍然是ABCD;

 

SingleTask: 栈内复用模式。这是一种单实例模式,这种模式下,只要activity在一个栈中存在,那么再次启动该activity也不会重新创建实例,和singleTop一样,会执行onNewIntent方法,并调至栈顶,clear掉该activity所在栈中上面的所有实例。

举例:(1) 栈S1中情况是     ABC,这时候C启动D(singleTask模式),并且  D所需的任务栈是S2,由于S2和D的实例都不存在,所以系统需要先创建任务栈S2,然后再创建D的实例并将其压入S2栈中;

(2) 如果D所需的任务栈是S1,D在S1中也没有实例,那么直接创建D实例执行所有生命周期并入栈,

(3) 如果D所需的任务栈是S1,并且当前任务栈S1中情况是ADBC,此时以singleTask模式启动D,系统会把D切换掉栈顶并调用其onNewIntent方法,同时singleTask默认有clearTop属性,会导致栈内D上面的activity全部出栈,这时候S1中最终情况是AD.

 

singleInstance:单实例模式。这是一种加强的singleTask模式,它除了有singleTask模式所有属性外,还加强了一点那就是具有此模式的activity只能单独存在一个栈中

举例:栈1中有activity A,启动具有singleInstance模式的activity B ,那么启动后情况是栈1:A ,栈2:B。

再次启动B,执行activityB的onNewIntent方法,启动后情况是栈1:A ,栈2:B。

 

废话少说,上代码,show me the fuck code !

Standard:

Activity A 默认启动模式为standard

内置button点击跳转新的Activity A ,A--A--A

连续点击两次跳转按钮查看log

查看堆栈  shell dumpsys activity

由此可知,每创建一次实例都会重新创建新的activity,结构图如下

SingleTop

Activity A跳转至activity B,然后再次打开Activity B, A--B--B

查看log

查看堆栈

可以看出虽然打开了两次Activity B,但并没有创建两个Activity B实例,所以当启动模式为singleTop的Activity位于栈顶时再次启动会执行onNewIntent方法并重复使用已存在的实例

SingleTask

Activity A跳转至activity B,然后再次打开Activity A,然后再次打开Activity B,  A--B--A--B

查看log

堆栈

可以看出两次打开Activity B 并没有生成两个实例,和singleTop相同执行了相同的ActivityB并执行onNewIntent方法,不同的是singleTask模式具有clearTop属性,A--B--A--B跳转后如果是standard模式栈内情况是A--B--A--B,由于singleTask模式具有clearTop属性再次打开ActivityB的时候AB出栈,栈内进而只留下AB

singleInstance  

Activity A跳转至activity B,然后再次打开Activity A,然后再次打开Activity B,  A--B--A--B

可以看出singleInstance模式具有singleTask模式的特性,不同的是singleInstance模式的Activity会单独开一个新栈,ActivityB单独运行在这个栈中,后续再次打开ActivityB也不会重新创建,除非这个单独的栈被销毁。

-------------------------------------扩展-----------------------------------------

TaskAffinity (任务相关性)

在启动模式中多次提到Activity运行的栈,什么是Activity所需要的任务栈呢?TaskAffinity这个参数标识了一个Activity所需要的任务栈的名字,默认情况所有Activity所需任务栈的名字是应用的包名。我们可以为每个Activity指定特定的任务栈,但这个值不能和包名相同,否则相当于没有指定。

当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和taskAffinity相同的任务栈中。

看个栗子

问:如果Activity A跳转至B,B 再跳转至C,C再跳转至A,然后A再打开B,这时候back两次会看到哪个Activity?

这个题可以作为面试题,答案是回到桌面,你猜到了吗?下面我们具体分下下:

A的启动模式是standard模式,没有设置taskAffinity,系统默认应用包名。由于我们为B和C指定了taskAffinity和启动模式,所以B和C是singleTask模式且具有相同的taskAffinity值为“com.xixiang.task1”,两个Activity处于同一个栈中。A启动B的时候按照singleTask模式规则,这个时候需要为B重新创建一个任务栈名为“com.xixiang.task1”。B启动C,按照singleTask模式规则,由于C所需任务栈和B所需任务栈位于同一任务栈并且栈已经创建,所以无须再创建新的任务栈,这时候系统创建一个新的实例C并将其入栈。接着C再启动A,A是standard模式,所以系统会为它创建一个新的实例并将其加到启动它的任务栈中,由于C启动了A,所以A会进入C的任务栈并位于栈顶,这个时候两个任务栈,一个名字为包名(栈1),一个名字为“com.xixiang.task1”(栈2),栈1中只有Activity A,栈2中为BCA,接下来A再启动B,由于B是singleTask,B需要回到任务栈顶,这时候CA出栈。所以到这里,点击back键的话B就出栈了,B所在的任务栈就不存在了,这个时候只能是回到后台任务栈并把A显示出来。但是现在A所在的栈是后台任务栈,不是B所在的前台任务栈,所以现在继续back键就回到桌面了。你猜对了吗?

我们用代码验证一下:

查看log

启动到最后的Activity B时候查看堆栈信息:

可以看出最后剩下两个Activity分别存在于两个不同的栈中,back一次返回到栈1中,再次back返回桌面



牛逼的人都懂得分享O(∩_∩)O ~~


更多进阶知识

《Android进阶之路---启动模式》

《Android进阶之路---IPC机制》

《Android进阶之路---View工作原理》

.................................

《java进阶之路----泛型》

《java进阶之路----并发》

..............................

长按二维码关注

公众号:Xixiang的进阶之路




更多进阶文章点击下面阅读原文获取~~

原创粉丝点击