Activity的启动模式

我们都知道,在默认情况下,当我们启动多个Activity的时候,这些Activity会被依次加入到任务栈中,当我们点击系统返回键,Activity又会按照后进先出的顺序依次出栈。
但是,如果我们多次启动同一个Activity,系统会重复创建多个实例,这样看起来是不是有点奇怪呢?系统设计者当然要考虑这个问题,因此启动模式应运而生。

目前Activity的启动模式有四种:standard、singleTop、singleTask和singleInstance。

  • standard 标准模式
    这是系统默认的启动模式,每次启动一个Activity,系统都会重新创建一个新的实例,并且加入到启动它的Activity所在的栈中。比如说在ActivityA中启动ActivityB(标准模式),那么ActivityB就会加入到ActivityA所处的任务栈中。

  • singleTop 栈顶复用模式
    在这种模式下,如果被启动的Activity已经位于栈顶,那么此Activity不会被重新创建,同时它的onNewIntent方法会被回调,通过此方法的参数可以获取请求信息。如果新Activity不是位于栈顶,那么她依然会重建。

假设现在任务栈中内情况是ABCD,D位于栈顶,A位于栈底。这个时候要启动D,假如D的启动模式是singleTop,那么栈内情况依然是ABCD;假如D的启动模式是standard模式,那么栈内情况变成ABCDD。

  • singleTask 栈内复用模式
    这是一种单实例模式,在这种模式下,只要被启动Activity在一个栈内,那么多次启动这个Activity都不会发生重建。和singleTop一样,系统会调用其onNewIntent方法。
    这个模式可能情况相对要复杂一些。假如现在要启动一个模式为singleTask的ActivityD,如果系统不存在D想要的任务栈,那么系统会创建一个任务栈,并把D压入栈底;假如系统此时正好存在D需要的任务栈,则判断栈内是否有实例存在,如果有实例,则将D调到栈顶,如果此时D上有其他Activity,则全部弹出任务栈,如果不存在实例,则创建实例D并放入栈中。举个例子:

现有任务栈S1,栈内有实例ABC,C为栈顶,A为栈底,此时D以singleTask模式要求启动。
1、假设D所需栈为S2,由于系统内没有S2栈,所以会先创建S2任务栈,然后新建D实例并且压入S2栈中。
D启动完成后:S1-ABC,S2-D。
2、假设D所需任务栈为S1,由于S1已经存在并且栈内没有D的实例,因此系统会创建D实例并且压入S1栈中。
D启动完成后:S1-ABCD。
3、假设D所需任务栈为S1,并且此时S1内情况为ADBC,由于S1内已经有D的实例存在,所以系统直接将D调到栈顶,并且依次出栈C、B。这是因为singleTask模式默认具有clearTop的效果。
D启动完成前:S1-ADBC。
D启动完成后:S1-AD。

  • singleInstance 单实例模式
    这是一种加强的singleTask模式,它除了具体所有singleTask模式的特性之外,最重要的一点是,具有此模式的Activity只能单独位于一个任务栈中

假设Activity A的启动模式为singleInstance,当A启动后,系统会为它创建一个新的任务栈,并把A压入新的栈中。由于栈内复用的特性,后续的请求都不会创建新的Activity。

Activity的启动模式_第1张图片

Activity的启动模式_第2张图片

在singleTask模式中,多次提到Activity所需任务栈,那么如何指定一个Activity所需任务栈?这要从一个参数说起:TaskAffinity(任务相关性),这个参数对应的值就是Activity所需任务栈名字,Activity默认所需的任务栈名字就是应用包名。任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态,用户可以将后台任务栈切换到前台。

  • 当TaskAffinity和singleTask模式配对使用的时候,它就是具有该模式的Activity当前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity属性相同的任务栈中。
  • 当TaskAffinity和allowTaskReparenting结合使用,这种情况比较复杂。当一个应用A启动了应用B的Activity,如果这个Activity的allowTaskReparenting为true,那么当应用B被启动,这个Activity会直接从应用A的任务栈转移到应用B的任务栈。

比如有两个应用A和B,A启动了B的Activity C,然后按Home键回到桌面,单击应用B的桌面图标,这个时候不会启动应用B的主Activity,而是直接显示被应用A启动的Activity C。也就是说C从A的任务栈转移到了B的任务栈中。

有两种方法可以为Activity指定启动模式,第一种是通过AndroidManifest.xml为Activity指定启动模式:


第二种是通过在Intent中设置标志位来为Activity指定启动模式:

Intent intent = new Intent(A.this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);

这两种方式有一定的区别,在优先级上,第二种方式要高于第一种,如果同时存在,以第二种为准;两种方式在限定范围上也有所不同,第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识,第二种无法为Activity指定singleInstance启动模式。

Activity的一些常用标志位

  • FLAG_ACTIVITY_NEW_TASK
    作用是为Activity指定singleTask启动模式

  • FLAG_ACTIVITY_SINGLE_TOP
    作用是为Activity指定singleTop启动模式

  • FLAG_ACTIVITY_CLEAR_TOP
    具有此标志位的Activity启动时,位于其之上的Activity都要出栈。如果Activity的启动模式为standard模式,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。

    Activity的启动模式_第3张图片
    与standard连用.png

    Activity的启动模式_第4张图片
    与singleTop连用.png

    Activity的启动模式_第5张图片
    与singleTask连用.png

    注:图片来源https://blog.csdn.net/yztbydh/article/details/80450615

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    具有这个标志位的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到某个Activity的时候可以使用这个标志位,其对应在AndroidManifest中的属性为android:excludeFromRecents=“true”。

你可能感兴趣的:(Activity的启动模式)