Activity的启动模式和任务栈解析

为什么需要启动模式?
在正常默认的情况下,我们启动了多个Activity之后,系统会为这些Activity分别创建实例,然后根据先后顺序依次压入任务栈,最后进栈的Activity在栈顶。当我们点击back键的时候,Activity就根据后进先出原则依次出栈然后显示到界面上,直至栈空退出到桌面。然而在千变万化的需求中,这种默认的规则不能满足我们的开发,于是Android提供了其他几种Activity的启动模式。
什么是启动模式?
启动模式,其实就是Android定义让Activity以怎样的规则去排列顺序,然后显示出来。Android提供了四种启动模式,即standard、singleTop、singleTask和singleInstance,下面先介绍这几种模式的含义:
1、standard:标准模式,也是系统默认的启动模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。被创建的实例,都符合正常情况下Activity创建的生命周期。同时需要注意的是,被新创建的Activity会默认属于创建它的那个Activity的任务栈。例如A创建了B,那么B就会压入A所属的任务栈中。当我们用ApplicationContext去启动standard模式的Activity的时候,就会报错。这是因为非Activity的Context并没有任务栈的存在。解决此问题,就是为待启动的Activity设置FLAG_ACTIVITY_NEW_TASK 标记位,这样就会以singleTask模式启动,并为该Activity创建一个新的任务栈。
2、singleTop:栈顶复用模式。以此模式启动,如果该Activity已经在栈顶了,那么不会创建新的实例,即该Activity的oncreate、onStart方法不会被调用,但是它的onNewIntent方法会被调用。如果该Activity没有在栈顶,那么它一样会被创建新的实例并压入栈顶。例如,栈中有ABCD四个Activity,D位于栈顶,这时候如果启动D,那么D就不会被重新创建,栈中依然是ABCD;如果启动B,那么B会被创建,此时栈中Activity的顺序是ABCDB。
3、singleTask:栈内复用模式。此模式启动的Activity,在一个栈中只会有一个实例存在。以此模式启动的Activity A,首先会去寻找是否存匹配的任务栈,如果不存在则创建新的任务栈,同时把A入栈。如果存在匹配的任务栈,那么就会查找栈中是否存在A的实例,如果存在,那么在A之前的任务都会被清除出栈,然后把A显示到栈顶,同时调用onNewIntent方法;如果不存在A,那么创建A的实例。例如,栈中有ABCD四个Activity,D位于栈顶,此时再以singleTask模式启动B,那么B前的就会出栈,栈中的Activity为AB。
4、singleInstance:单实例模式。这是一种加强的singleTask,它的加强之处在具有此模式的Activity,只能单独地位于一个新的任务栈中,然后该Activity独自在栈中,后续的请求均不会创建该Activity的新实例,除非该任务栈被系统销毁。

什么是Activity的任务栈?我们多次提到任务栈这个东西,要了解任务栈,先要知道一个参数:TaskAffinity,可以称之为任务相关性。这个参数标识了一个Activity任务栈的名字,默认情况下,所有Activity任务栈的名字为应用的包名。但是我们可以自己设置这个TaskAffinity参数,取一个和包名不同的名字,然后抵用singleTask启动模式,创建一个新的栈。注意TaskAffinity只能和singleTask启动模式同时使用才有作用。此外,任务栈分为前台任务栈和后台任务栈,后台任务栈的Activity处于暂停状态,用户可以通过切换将后台任务栈转换成前台任务栈。亲测发现,后台任务栈可以有多个,当我们打开一个应用,然后直接按home键的时候,此应用的任务栈就会变成后台任务栈保存。

我们再来运行一个实例,有三个Activity:MainActivity 、SecondActivity、ThirdActivity,分别命名为A、B、C,其中B和C都是用的singleTask模式,并且设置了taskAffinity属性:

 <activity
            android:name="com.zhonghong.activity.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity 
            android:name="com.zhonghong.activity.SecondActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.yys.task1">

        </activity>

        <activity 
            android:name="com.zhonghong.activity.ThirdActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.yys.task1">

        </activity>

我们先启动A,然后在A中启动B,在B中启动C,在C中启动A,然后在A中再启动B,点击back键会发现,出现A,再点击back键,退出桌面。
我们分析下过程:首先常规启动A,创建任务栈task0;然后singleTask模式启动B,创建任务栈task1;创建C,入栈task1;standard模式创建A,入栈task1,现在任务栈task1为BCA,任务栈task0为A;singleTask创建B,于是C和A需出栈task1,task1中Acticity为B;按back键后,task1中B出栈后,task1就空了并被销毁,此时只能调度后台任务栈task0,并把task0中的A显示出来;再按back键,此时task0清空,最后只能调度桌面所在的任务栈,并且把launcher桌面显示出来。至此,整个任务调度完毕,我们也对任务栈和特殊的启动方式有了一定的理解。

猜你喜欢

转载自blog.csdn.net/yus201120/article/details/73833257