【Android Activity】Activity的启动模式

一、Activity 的启动模式

安卓是采用任务栈来管理activity的,默认情况下多次启动同一个activity系统会重复创建这个activity的实例,并把每个实例依次入栈。为了避免activity实例的重复创建、应付特殊的场景、安卓为activity设计了启动模式。

1、启动模式

1、standard:
标准启动模式,系统默认。每次启动一个activity系统都会重新创建一个新的实例,不管这个ativity的实例是否已经存在。

2、singleTop:
栈顶复用模式,这种模式下如果新的activity已经位于任务栈的栈顶,那么此activity不会重新创建实例即onCreate、onStart不会回调,同时会走他的onNewIntent方法回调。如果activity的实例已经存在站内,不是位于栈顶,还是会重新创建activity的实例的。

3、singleTask
站内复用模式,这是一种单利模式,这种模式下,只要activity实例在栈中存在,那么多次启动此activity都不会重新创建此 activity的实例,多次启动时系统会调用onNewIntent方法
具体理解:
ActivityA被设置为SingleTask启动模式,当系统收到开启A的请求后,系统会寻找是否存在A想要的任务栈:

1、如果不存在就重新创建一个任务栈,然后创建A的实例,吧实例放入任务栈中。
2、如果存在A所需的任务栈,这时查找A是否在栈中有实例存在,如果有实例存在系统会把A调到任务栈栈顶,同时调用它的onNewIntent方法。如果实例不存在就创建A的实例,吧A压入栈。(具体栗子如下图)

在这里插入图片描述

4 、singleInstance
单实例模式,具有singleTask的全部性质外,还加强了一点:具有此启动模式的activity只能单独存在一个任务栈中。换句话说比如ActivityA是singleInstance模式,当A启动后系统会为他创建一个新的任务栈,然后A独自运行在这个任务栈中,由于站内复用特性,后续的请求都不会创建新activity,除非这个独特的任务栈被系统销毁。

3、任务栈

什么是activity所需的任务栈呢?这要从一个参数说起:TaskAffinity(任务相关性),这个参数标识了任务栈的名字。默认情况下所有的activity所需的任务栈名字都是应用包名。当然我们也可以单独为activity指定这个属性,但是属性值不能和包名相同,否则就相当于没有指定。

(1)TaskAffinity的使用

1、在manifest文件的activity标签下指定。
2、这个属性主要与SingleTask启动模式或者allowTaskReparenting属性配对使用其他情况下没有意义。

  • taskAffinity 与 singleTask 配对使用:如果待启动的activity设置了这两个属性 ,这个 Activity就会在 taskAffinity设置的任务栈中。
  • taskAffinity 与 allowTaskReparenting 配对使用:当一个应用 A 启动了应用 B 的某个 Activity 后,如果这个 Activity 的 allowTaskReparenting 属性为 true 的话,那么当应用 B 被启动后,此 Activity 会直接从应用 A 的任务栈转移到应用 B 的任务栈中。这个属性主要作用就是将这个 Activity 转移到它所属的任务栈中。这里不好理解栗子如下图和代码

3、默认情况下TaskAffinity属性值为包名。即sigleTask模式下任务栈默认为启动他的activity所在任务栈,当待启动activity的TaskAffinity与启动他的activity的TaskAffinity不同时,待启动的activity所在任务栈就不再是启动它的activity所在的任务栈了。

在这里插入图片描述

//应用A#MainActivity 
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn.setOnClickListener {
            // 开启应用B的ActivityC
            val intent = Intent()
            intent.action = Intent.ACTION_VIEW
            intent.addCategory(Intent.CATEGORY_DEFAULT)
            intent.addCategory("com.sunnyday.activitytask")
            startActivity(intent)
        }
    }
}
//应用B的manifest
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <!--
          1、设置allowTaskReparenting = true
          2、 android:taskAffinity //默认为包名
      -->
        <activity android:name=".ActivityC"
            android:exported="true"
            android:allowTaskReparenting="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.sunnyday.activitytask"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

(2) 任务栈分类:

  • 前台任务栈:前台activity所处的任务栈即为前台任务栈。
  • 后台任务栈:后台activity所处的任务栈即为后台任务栈。后台任务栈中activity处于暂停或者stop状态)

(3)前后台任务栈结合SingleTask模式栗子

假设目前两个任务栈,前台任务栈内有AB,后台任务栈有CD这里假设CD的启动模式均singleTask
1、现在请求D那么整个后台任务栈都会被切换到前台。如下如图一。
2、如果不是请求D而是请求C情况就不一样了。如下图二。

在这里插入图片描述
在这里插入图片描述

4、如何指定启动模式
  • xml中activity节点配置(不配置默认为standard)

  • intent中设置标志位来为Activity指定启动模式(如下图)

在这里插入图片描述

二者区别:
1、优先级上代码配置高于xml配置,两种同时存在时以代码为准。
2、两种方式在限定范围上有所不同,第一种方式无法为activity设定Intent.FLAG_ACTIVITY_CLEAR_TOP 标识,第二种方式无法为activity指定singleInstance启动模式。

7、activity的Flags
flag说明
FLAG_ACTIVITY_NEW_TASK为activity指定singleTask启动模式,效果和在xml中指定的效果相同。
FLAG_ACTIVITY_SINGLE_TOP为 Activity 指定 singleTop 启动模式,其效果和在 xml 中指定启动模式相同
FLAG_ACTIVITY_CLEAR_TOP具有此标记位的 Activity,当启动它时,同一个任务栈中所有位于它上面的 Activity 都要出栈。这个模式一般需要和 FLAG_ACTIVITY_NEW_TASK 配合使用,在这种情况下,被启动的 Activity 实例如果已经存在,那么系统就会调用它的 onNewIntent。如果被启动的 Activity 采用 standard 模式启动,那么它连同它之上的 Activity 都要出栈,系统会创建新的 Activity 实例并放入栈顶SingleTask模式默认有这个flag。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS具有这个标记的 Activity 不会出现在历史的 Activity 的列表中,当某些情况下我们不希望用户通过历史列表回到我们的 Activity 的时候这个标记比较有用。它等同于在 xml 中指定 Activity 的属性 android:excludeFormRecents=“true”

二、思考

1、TaskAffinity与allowTaskReparenting到底如何使用

没探究安卓源码之前这里只需要明白:
1、TaskAffinity与SingleTask模式一起使用。场景是当你想要开启一个新的任务栈
2、allowTaskReparenting与TaskAffinity一起使用。场景如上应用A跳转用用B的ActivityC栗子。
ps:除了如上使用方式一般其他使用方式无意义。

2、默认情况下被启动的activity 运行在启动它的activity所在任务栈中?service、广播开启的activity 需要添加FLAG_ACTIVITY_NEW_TASK flag?

正确,对的。

3、如何标识activity的所处的任务栈

使用taskid获取,这个唯一标识。TaskAffinity也可获取单不是唯一标识,因为默认值都相同。这个值只是在singleTask模式下影响activity的taskid。

 1、activity的方法
 
 getTaskId() // 获取当前activity的taskid
 
 2ActivityInfo 的方法
 
    fun dumpTaskAffinity() {
        try {
            val info = this.packageManager
                .getActivityInfo(componentName, PackageManager.GET_META_DATA)
             //获取activity的taskAffinity值
            Log.i("TAG", "taskAffinity:" + info.taskAffinity)
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }

    }
3、查看所有activity的详细信息

adb shell dumpsys activity a

The end

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值