关于 <activity> 的 taskAffinity 属性一些情景测试记录

下列场景的测试环境:
1、模拟机,Android 版本 8.0.0
2、开发环境:

compileSdkVersion 28
targetSdkVersion 28

1、taskAffinity 用于设置 activity 对于 Task 的亲和力,而 Task 的亲和关系由 Task 中的根 Activity 确定,即根 Activity 的 affinity 决定着 Task 的 affinity 值。

2、但是并不是设置了 taskAffinity 值,Activity 在启动的时候就会处于与值对应的 Task 中。一般情况下,Activity B 会处于启动它的 Activity A 对应的 Task 中,即使 B 设置的 taskAffinity 值与 A 的不同。

3、有如下情景,即在 Activity A 中启动 Activity B,且 A 和 B 的 luanchMode 都不为 singleInstance,此时:

  • B 为 singleTask 且其 taskAffinity 值与 A 的相同,则 B 会处于 A 对应的 Task 中;
  • B 为 singleTask 但是其 taskAffinity 值与 A 的不相同,此时如果 taskAffinity 值对应的 Task 不存在,则会先创建 taskAffinity 值对应的 Task,再将 B 推入其中;否则,会将 B 直接推入 taskAffinity 值对应的 Task 中。
  • B 为非 singleTask,此时其 taskAffinity 值与 A 的相同与否,都会处于 A 对应的 Task 中。

(对于 singleInstance 或者 singleTask 类型的 Activity,在整个系统中,都只会存在一个实例。而且,singleInstance 类型的 Activity 对应的 Task 有且仅有该 Activity 对应的实例。)

4、对于 taskAffinity,应该是只对 singleTask 有效,而对于 singleTop、standard 类型的 Activity,即使设置了 taskAffinity,且 taskAffinity 值对应的 Task 已经存在,但是启动 Activity 的时候,该 Activity 是处于启动它的 Activity 对应的 Task 中的。而对于 singleInstance,假设有 Activity A、B 设置的 taskAffinity 值一样,但是 B 为 singleInstance,此时从 A 启动 B 时,B 会处于一个单独的 task 中。

有如下代码可以测试:

<activity
    android:name=".ActivityA"
    android:taskAffinity="zzq.task1" />
    
<activity
    android:name=".ActivityB"
    android:launchMode="singleTask"
    android:taskAffinity="zzq.task2" />

<activity
    android:name=".ActivityC"
    android:launchMode="singleTop" 
    android:taskAffinity="zzq.task1" />

此时先启动 A,在 A 中启动 B,在 B 中启动 C,且在启动的时候分别通过 Activity#getTaskId() 打印每个 Activity 的 task id,此时 A 的 taskId 为 X1,而 B、C 的为 X2。即使将 C 的 taskAffinity 改为 zzq.task3,也与前面的结果一致。

5、关于 taskAffinity 对于 singleInstance 的影响:

<activity
    android:name=".ActivityA"
    android:taskAffinity="zzq.task1" />
    
<activity
    android:name=".ActivityB"
    android:launchMode="singleInstace"
    android:taskAffinity="zzq.task2" />

<activity
    android:name=".ActivityC"
    android:taskAffinity="zzq.task2" />

对于上述测试代码,即使 C 和 B 的 taskAffinity 值一样,但是因为 B 是 singleInstance 模式的,因此在 B 中启动 C 的时候,C 会处于一个新的 Task 中。

而如果将 C 的 taskAffinity 改为 zzq.task1,则 C 会处于 A 所处的 Task 中。

6、根据所阅读的文章,taskAffinity 应该是在两种情景下起影响作用:

(1)对于 singleTask 模式的 Activity,即 launchMode 为 singleTask 或者 Intent 的 FLAG 为 FLAG_ACTIVITY_NEW_TASK。这一点通过 3、4、5 点可以确认。

(2)另一个场景则是结合 <activity>android:allowTaskReparenting 属性。

allowTaskReparenting 用于设置已经启动的 Activity,当其设置的 taskAffinity 值对应的 Task 每次 转移到前台时该 Activity 是否从已有的 Task 中转移回其 taskAffinity 值对应的 Task 的栈顶。true 表示转移。

比如,有两个应用 A1 和 A2,其中:

// 对于应用 A1
<activity android:name=".ActivityA"
    android:taskAffinity="zzq.task1">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

// 对于应用 A2
<activity android:name=".ActivityB"
    android:taskAffinity="zzq.task2">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity
    android:name=".ActivityC"
    android:allowTaskReparenting="true"
    android:taskAffinity="zzq.task1">
    <intent-filter>
        <action android:name="com.zzq.test" />               
        <category android:name="android.intent.category.DEFAULT" />
                   
    </intent-filter>
</activity>

当先打开应用 A2 时,显示的是 Actvity B,然后在 B 中启动 C 的实例 C_1,在 C_1 中再启动一个 C 的实例 C_2,此时 C_1C_2 会处于 B 的 Task 中,此时按下 HOME 键回到桌面,再打开应用 A1(A1 原来没有打开过,即没有处于后台),此时因为 Activity C 的 taskAffinity 值与 A 的一致,因此 C_1C_2 两个实例会从 B 的 Task 中转移到新的 Task 中,(此时也对应一个新的返回栈,该返回栈包含新的Task),但是此时新的 Task 中只有 C_1C_2(按照从栈底到栈顶的顺序),MAIN Activity A 并没有生成(更准确的说,此时应用 A1 的进程都不存在,使用 adb 命令查看进程对比发现),而此时应用 A2 的返回栈(Back Stack)中就只剩原本的 B 了。

而 C 如果为 singleTask、singleTop 的时候,也是一样,虽然 C 会转移,但是此时 A1 的返回栈只有 C,A1 进程也没有产生。

当然,要记住上述前提是 A1 还未被打开过。

而如果是先将 A1 打开(C 所亲和的 Task 1 已经产生,且 Task 1 栈底为 A),然后按下 HOME 键回到桌面,此时 A1 就位于后台,然后在打开 A2,在 B 中启动 C,此时因为 C 所亲和的 Task 1 已经存在了,则会把该 C 会推入 Task 1 中,然后把整个 Task 1 都放到此时的返回栈的栈顶,因为此时返回栈中为 B,A,C(从栈底到栈顶),如果又按下 HOME,再切换回 A1,则又会把 Task1 给调回 A1 对应的返回栈。

但是,如果 C 为 singleInstance 模式,不管是先打开 A1,还是后打开 A1,C 都会转移,但是此时不是转移到 A 对应的 Task 中,即使有相同的 taskAffinity(因为 singleInstance 模式的特殊性,C 会拥有自己独立的 Task),当打开 A1 的时候,都显示的 A,而此时 C 会转移到后台。


参考文章:
1、https://developer.android.com/guide/topics/manifest/activity-element.html#reparent
2、《Android 开发艺术探索》
3、《Android 进阶解密》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值