Activity的启动模式和Intent.FLAG_ACTIVITY_NEW_TASK理解

为什么需要启动模式?
在正常默认的情况下,我们启动了多个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 标记位,为该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的新实例,它是在整个系统是全局的,除非该任务栈被系统销毁。一般的应用很少用到这个模式,比如像智能电视的Launcher这样的Activity,任何的应用都可以切换到Launcher中去,然后做一些操作,然后返回键再回到之前的应用中去。

什么是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桌面显示出来。至此,整个任务调度完毕,我们也对任务栈和特殊的启动方式有了一定的理解。

这里,还要再解释下我们JAVA代码中启动Activity的时候,所用到的启动模式:

Intent.FLAG_ACTIVITY_NEW_TASK :
首先会查找是否存在和被启动的Activity具有相同的任务相关性的任务栈(即taskAffinity,注意同一个应用程序中的activity的任务相关性默认是一样的,除非修改),如果有,刚直接把这个栈整体移动到前台,并把此它上面的Activity出栈;如果没有,则新建一个栈来存放被启动的activity。

Intent.FLAG_ACTIVITY_SINGLE_TOP
这个属性,和singleTop模式一样。

Intent.FLAG_ACTIVITY_CLEAR_TOP
lunchMode中没有对应的模式,如果栈中存在此Activity,那么就会把在它上面的Activity移除栈。singleTask自带此属性。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值