美文网首页
Activity的启动模式

Activity的启动模式

作者: 程自舟 | 来源:发表于2017-05-09 00:01 被阅读0次

    Activity为什么需要启动模式?在默认情况下,当多次去请求同一个Activity时候,系统会创建多个实例并把它一一放入到任务栈中,当按下back键的时候,Activity会一一回退。因为“栈”是一种后进先出的结构。当Activity默认启动时候,系统会重复创建多个实例,为避免这种情况,所以Android提供了四种启动模式来修改系统的默认启动模式:standard,singleTop,singleTask,singleInstance。

    1.standard,标准的启动模式,即系统的默认启动模式,每次启动都会创建一个实例,不管实例是否存在,创建的实例生命周期符合Activity正常的生命周期。典型的多实例体现,一个任务栈中可以有多个实例,每个实例可以有不同的任务栈。
    举例:Activity A 启动了ActivityB(standard模式),那么B会进入到A栈中。
    注:当用ApplicationContext去启动standard的时候,会抛出异常:

    Paste_Image.png

    这是由于ApplicationContex没有所谓的任务栈,此时应给待启动Activity添加FLAG_ACTIVITY_NEW_TASK标记位,这样Activity启动会为它创建一个新的任务栈,实际上采用了singleTask模式启动。

    2.single Top:栈顶复用模式。在这种模式下,如果新Activity已经位于任务栈栈顶,那么Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法可以取出当前请求信息。

    注:此模式下的Activity的onCreate,onStart不会被调用。如果新Activity不在栈顶,那么仍会重新创建。

    举例:栈内有ActivityA,B,C,D。A位于栈底,D位与栈顶。如果D启动模式为standard,那么为ABCDD。如果D启动模式为singleTop,那么为ABCD。

    3.singleTask,栈内复用模式。这是一种单例模式,在此模式下,只要Activity在一个栈中存在,那么多次启动Activity都不会创建实例,和singleTop相同,系统也会回调onNewIntent。

    举例:ActivityA启动模式为singleTask,系统会寻找是否存在A想要的任务栈,如果不存在就重新创建一个栈,然后创建A的实例并放入栈中。如果存在A所需的任务栈,则会去检查栈中是否存在A的实例,如果存在,系统调用A的onNewIntent,并把A调到栈顶。如果不存在实例,就创建实例并压入栈中。
    具体情况举例:

    (1)任务栈S1有ABC,D以singleTask模式请求启动后,D所需的任务栈为S2,S2不存在,系统会创建S2任务栈和D实例并入栈S2。
    (2)D所需的任务栈为S1,那么系统检查S1里是否存在D实例,如果不存在,创建D实例并入栈S1。
    (3)与(2)同,但是D实例存在,调用D的onNewIntent,并且此时D位于S1任务栈的栈顶。同时由于singleTask默认具有clearTop的效果,D上面的Activity会全部出栈,如ADBC会变成AD。

    4.singleInstance:单实例模式。singleTask模式的加强版,不同的是,此模式的Activity只能单独位于一个任务栈中。

    举例:
    Activity A是singleInstance启动模式,那么A启动后,系统会为A单独创建一个新的任务栈,A独自在这个新任务栈中,且由于栈内复用特性,后续请求都不会重新创建A,除非这个新任务栈被系统销毁。

    思考问题:假设有两个任务栈,S1,S2。S1是前台任务栈AB,S2是后台任务栈CD。CD启动模式均为singleTask,那么现在请求启动C和请求启动D有什么区别?
    个人理解:如果请求D,那么后台任务切换到前台,那么后退列表变为ABCD,如果请求C,那么C会把D给清除掉(singleTask的clearTop的效果),那么后退列表就变成ABC。

    什么是singleTask的所需任务栈呢?
    即一个参数:Taskfinity(任务相关性),此参数标识了一个Activity所需要任务栈的名字,默认情况下,所有Activity所需任务栈都是包名。Activity也可以单独指定Taskfinity属性,但是该属性必须与包名不同,否则指定无意义。Taskfinity必须和singleTask启动模式或者和allowTaskReparenting属性配对使用,其他情况也无意义。任务栈分前台任务栈和后台任务栈。

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

    当Taskfinity和allowTaskReparenting结合使用,会产生特殊情况。当应用A启动了B的某个ActivityC后,如果C的allowTaskReparenting属性为true,那么当应用B启动后,C会直接从应用A移动到应用B的任务栈中。通俗来说,此时应用B启动后并不会启动B的主Activity,而是重新显示在A里已启动的C(此时C从A任务栈转移到到B任务栈,由于是A启动C,C只能在A任务栈,但是C又属于B,而Taskfinity值又肯定不能和A相同(包名不允许相同),所以当B启动后又会创建新任务栈,这时系统会发现C的任务栈已经被创建了,所以C会移动到B任务栈)。

    至此,我也明白了工作中调用第三方app后(如地图导航)返回后仍是自己APP的界面以及重新进入第三方app直接显示之前调用界面的原因。

    指定Activity的启动模式有两种,一种是通过AndroidMenifest为Activity指定启动模式:

    Paste_Image.png

    另一种通过intent中设置标志位来指定启动模式:

    Paste_Image.png

    二者区别:
    intent指定优先级高于AndroidMenifest指定,两者若同时存在,以intent为准。
    限定范围不同:AndroidMenifest指定无法直接设定FLAG_ACTIVITY_CLEAR_TOP标识,而intent无法为Activity指定singleInstance模式。

    相关文章

      网友评论

          本文标题:Activity的启动模式

          本文链接:https://www.haomeiwen.com/subject/waamgttx.html