Android四大组件之Activity-启动模式

1.Activity的启动模式

当我们多次调用同一个Activity时,系统会重复创建多个实例并把它们一一放入任务栈中,这种方式显然不符合我们的设计要求。所以Android在设计时就提供了四种启动模式来解决此问题。

四种启动模式分别如下:

  1. standard-标准模式也是默认模式
    每次启动一个Activity都会创建新的实例并压入任务栈,onCreate,onStart,onResume都会被调用。每个任务栈可以有多个实例,每个实例也可属于不同的任务栈。例如:
    A->B,B为standard模式,B即属于A的任务栈。
    A B C D 再次启动A(standard模式)
当前任务栈存在的元素 启动后的任务栈存在的元素
A B C D A B C D A
  1. singleTop-栈顶复用模式
    此模式下,比如新的Activity已经位于栈顶,那么此Activity不会被重新创建,会回调它的onNewIntent方法,它的onCreate,onStart不会被系统调用。如果新的Activity不是位于栈顶,那么它还是会被重新创建。例:
    A B C D 再次启动D(singleTop模式)
    A B D C 再次启动D(singleTop模式)
当前任务栈存在的元素 启动后的任务栈存在的元素
A B C D A B C D
A B D D A B D C D
  1. singleTask-栈内复用模式
    单实例模式,只要Activity在一个栈中存在,多次启动都不会重新创建实例,系统会回调onNewIntent方法。
    如果要启动一个启动模式为singleTask的Activity A,先判断是否存在A所需的任务栈,不存在->新创建任务栈并把实例A压入。如果存在,判断A是否在栈中存在实例,存在移到栈顶,并将之前的实例出栈,如果不存在实例,创建并压入栈。
任务栈S1存在A B C,启动D(singleTask模式)(所需任务栈S2),因为S2与D实例均不存在,所以系统会新建任务栈S2并创建D压入S2。
任务栈S1存在A B C,启动D(singleTask模式)(所需任务栈S1),启动D后的S1为A B C D。
任务栈S1存在A D B C,启动D(singleTask模式)(所需任务栈S1),启动D后的S1为A D。

使用:

<activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

 override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        Log.d(TAG, "--onNewIntent--")
    }

在这里插入图片描述

可以看出MainActivity始终没有被重新创建

  1. singleInstance-单实例模式
    加强的singleTask模式,拥有singleTask的所有特点且只能单独的位于一个任务栈中。

特殊情况

🐖:现在有S1-前台任务栈,S2-后台任务栈(singleTask模式)。S1有A B,S2有C D。
现在启动D,S2整个任务栈会切换至S1中,即S1存在 A B C D,依此按下返回键实例一一出栈。
现在启动C,S2整个任务栈会切换至S1中,即S1存在 A B C,依此按下返回键实例一一出栈。

2.任务栈

前面所说的Activity所需任务栈是什么?即TaskAffinity参数:这个参数标识了一个Activity所需任务栈的包名。此属性主要与singleTask启动模式或者allowReparenting属性配对使用。

1.当与singleTask配对使用时,启动的Activity会运行在名字与TaskAffinity相同的任务栈中。
2.当与allowReparenting配对使用时,情况比较特殊。
现有应用A与B(存在Activity C),现在A启动B的C,点击Home键。点击B 会启动C。--C从A的任务栈转移到了B的任务栈。
3.当启动模式为Standard以及SingleTop时指定TaskAffinity属性不生效

简单使用:
A为standrad
B为singleTask TaskAffinity值为”com.wdl.test“。模拟过程A->B->A

    <activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize"
            android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Main2Activity"
            android:taskAffinity="com.wdl.test"
            android:launchMode="singleTask"/>

控制台输入adb shell dumpsys activity

在这里插入图片描述

发现此时存在两个任务栈 一个为包含B A的S1(com.wdl.test),另一个为只有A的S2 (com.wdl.kt1)

分为2类:

  • 前台任务栈
  • 后台任务栈,位于暂停状态

3.如何给Activity指定启动模式

  1. 通过AndroidMenifest.xml为Activity指定启动模式
  <activity android:name=".Main2Activity"
            android:launchMode="singleTask"/>
  1. 在Intent中设置标志位为Activity指定启动模式
  val intent = Intent(this,MainActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            startActivity(intent)

常用的标志位有:

作用
FLAG_ACTIVITY_NEW_TASK 指定singleTask启动模式
FLAG_ACTIVITY_SINGLE_TOP 指定singleTop启动模式
FLAG_ACTIVITY_CLEAR_TOP 此Activity(singleTask)之前的实例全部要出栈; Activity(standard)之前与本身的实例全部要出栈,重新创建实例并入栈
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 具有此标记的Activity不会出现在历史Activity中

二者的区别:
1.优先级上第二种方式高于第一种方式
2.限定范围上有所不同
例:第一种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识;第二种方式无法为Activity指定singleInstance模式

案例一:

有三个activity
A(singleInstance) B(singleTop) C(Standard)

启动顺序:
C -> B -> A ->B ,退出时的界面,以及任务栈的个数,back键的回退情况如何?

配置文件:

<activity android:name=".CActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".BActivity"
            android:launchMode="singleTop" />
        <activity
            android:name=".AActivity"
            android:launchMode="singleInstance"
            android:taskAffinity="com.wdl.demo"/>

直接上图吧:
在这里插入图片描述

任务栈如下:
在这里插入图片描述

详细分析:
压栈过程:
C:S1(C)前台任务栈
C->B:S1(C,B)前台任务栈
C->B->A:S2(A)前台任务栈,S1(C,B)后台任务栈
C->B->A->B:S2(A)后台任务栈,S1(C,B)前台任务栈

出栈过程:
一次Back键:S2(A)后台任务栈,S1(C)前台任务栈 B出栈
一次Back键:S2(A)前台任务栈 C出栈
一次Back键:finish A出栈

展开阅读全文

没有更多推荐了,返回首页