taskAffinity 属性详解

  这篇文章用来记录一下自己对 taskaffinity 属性的理解,以帮助和我有相同困惑的同学。不对之处还请各位看客指出,我会及时更正。

一、本文目的

本篇文章的目的是为了 搞清楚,哪些情况下开启一个 Activity 会在新的 task 运行,哪些情况下会继续在原来的task 运行。

二、相关基础知识

知识点 1

每个 Activity 运行时都有一个其归属的 task栈,我们可以用 activity.getTaskId() 的方法得到当前 activity 的taskId。如果两个 activity 的 taskId 不同,则他们肯定不会属于同一个 task。

为了方便,我们在 Application 中注册生命周期回调,类似这样,我们打印出当前 activity 和其归属的 taskid。

public class MyApplication extends Application {
    private static final String  TAG_APP = MyApplication.class.getSimpleName();
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG_APP,"MyApplication#onCreate"+Thread.currentThread().getName();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            //已过滤无用代码,只在onresume 读取相关数据
            @Override
            public void onActivityResumed(Activity activity) {
                Log.d(TAG_APP,"onActivityResumed+"+activity.getClass().getSimpleName()+"####taskid = "+activity.getTaskId());
            }
        });

    }
}

知识点 2

taskAffinity 的使用方式如下,


image.png

如上图所示,taskaffinity 可以单独对一个 activity 使用,代表该 activity 所想归属的 task;
也能对application 使用,代表该 application 内声明的所有 activity 都归属于这个task。

如果 activity 组件没有声明 taskAffinity 的话,该 activity 的 taskAffinity 属性也是有默认值的。如果 application 指定了 taskAffinity 值,默认值就是 application 指定的 taskAffinity 值;如果 application 未指定的话,默认值就是 manifest 中声明的包名(package 对应的字符串)。

知识点 3

Android 手机的任务列表就是根据不同 task 弹出的,我们可以根据任务管理器有几个 item 图标,来知道我们开启了几个 task。

知识点 4

是不是我指定了一个 Activity 的 taskAffinity 值(跟包名不同),运行该 Activity 时,是否就会新开这个 task栈呢?

答案是否定的,一个 Activity 运行时所归属的task,默认是启动它 的那个Activity 所在的 task(下文将会验证)。

知识点 5

taskAffinity 单独使用并不会生效。
要想其生效,需要配合其他属性使用,或者配合 Intent.FLAG_ACTIVITY_NEW_TASK,或者配合
allowTaskReparenting 。使用时用其中的一个就行,下面将详细介绍这两个属性。

三、Intent.FLAG_ACTIVITY_NEW_TASK

Intent.FLAG_ACTIVITY_NEW_TASK 使用方式如下,

Intent intent = new Intent(this,IntentTimeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

3.1 FLAG_ACTIVITY_NEW_TASK 解析规则

首先说下这个规则是根据测试结果反推出来的,不对之处还还请指出(捂脸。。。)

==当 AMS 发现启动了一个带有 FLAG_ACTIVITY_NEW_TASK 标签的 Activity 时,会先去寻找当前是否存在这个 Activity 的 task 值(这个值具体是什么可看 知识点2),如果不存在的话,就会创建该task,如果存在就省去了创建 task 这个步骤。然后在把要启动的 Activity 添加到 task 中。

3.2 测试case和结果

下面开始我们的测试,测试结果为过滤后的log日志,并给出相应分析。


我们假定都是 Activity A 跳转到 Activity B 中,A没有指定 taskAffinity 属性,B 的launchMode 为standard。

case1: A、B 属同一App, intent 未指定 FLAG_ACTIVITY_NEW_TASK,B 未指定 taskAffinity 属性
D/MyApplication: onActivityResumed+MainActivity####taskid = 61 
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 61

可以验证:一个Activity 归属的task 是由 启动它的 Activity 所决定的。

case2: A、B 属同一App,intent 未指定 FLAG_ACTIVITY_NEW_TASK,B 指定 taskAffinity 属性,但与包名相同
D/MyApplication: onActivityResumed+MainActivity####taskid = 62 
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 62

可以验证,一个 Activity 的默认 task 值就是 manifest 定义的包名。

case3: A、B 属同一App,intent 未指定 FLAG_ACTIVITY_NEW_TASK,B 指定 taskAffinity 属性,但与包名不同
D/MyApplication: onActivityResumed+MainActivity####taskid = 63
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 63

可以验证:不指定 FLAG_ACTIVITY_NEW_TASK的话, 即使 taskAffinity 不同,一个Activity 归属的task 仍然是由 启动它的 Activity 所决定的。

case4: A、B 属同一App,intent 指定 FLAG_ACTIVITY_NEW_TASK,B 未指定 taskAffinity 属性
D/MyApplication: onActivityResumed+MainActivity####taskid = 64
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 64

可以验证:即使 使用了 FLAG_ACTIVITY_NEW_TASK,但由于两者的 taskAffinity 相同,所以仍然不会开启一个新的task。

case5: A、B 属同一App,intent 指定 FLAG_ACTIVITY_NEW_TASK,B 指定 taskAffinity 属性,且和包名不同
D/MyApplication: onActivityResumed+MainActivity####taskid = 65
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 66

可以验证:开启一个新task 的条件是 FLAG_ACTIVITY_NEW_TASK 和 taskAffinity 不同 缺一不可。


case6: A、B 属同一App,intent 未指定 FLAG_ACTIVITY_NEW_TASK,B 未指定 taskAffinity 属性,B启动模式为 singletask or singletop
D/MyApplication: onActivityResumed+MainActivity####taskid = 67
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 67

可以得出:未指定 FLAG_ACTIVITY_NEW_TASK 和 新的 taskAffinity 时,这两种启动模式对task 没有影响

case7: A、B 属同一App,intent 未指定 FLAG_ACTIVITY_NEW_TASK,B 未指定 taskAffinity 属性,B启动模式为 singleinstance
D/MyApplication: onActivityResumed+MainActivity####taskid = 70
D/MyApplication: onActivityResumed+KeyboardActivity####taskid = 71

可以得出:
singleinstance 启动模式本身就是会开启一个新的task 装载 这个Activity,且task 中只有这一个 Activity。
经判断得知,AMS 是先对 launchMode 做判断 再处理 FLAG_ACTIVITY_NEW_TASK 的,如果是 singleinstance ,则会直接开启一个task。


上面七个 case 均是在同一个app 内的,现在考虑跨进程调用的情况,A在 app1,B在app2,此时 B 的默认 task 肯定是和 A 不同的
我们可以通过隐式启动的方式启动B,B 仍然是标准启动模式。
类似这样

//App1中 在Activity A 中我们这样定义跳转方法
public void onClickApp2(View v){
        Intent intent = new Intent("xxx.lzq");//action 自己随便定义就行,但要保证 跟 B 的 intent-filter 是相同的。
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        startActivity(intent);
    }
    
//app2 中 manifest文件这样定义
<activity android:name=".Main2Activity">
            <intent-filter>
                <action android:name="xxx.lzq"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

++下文 所有的 App1的log标识为 MyApplication,App2 的标识为 MyApplication2。++

case 8: intent 未指定 FLAG_ACTIVITY_NEW_TASK
D/MyApplication: onActivityResumed+MainActivity####taskid = 74
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 74

可以得出:case 8 与 case 3 的本质是相同的,仅仅是 A 和 B 的taskA 属性不同,所以没有开启新的task。
我们还可以看出,task 是可以跨进程的,即一个 task 中的 Activities 是可以运行在不同的进程中的。(关于 A 和 B 不在同一个进程读者可自行验证)

case 9: intent 指定 FLAG_ACTIVITY_NEW_TASK
D/MyApplication: onActivityResumed+MainActivity####taskid = 76
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 77

可以得出:case 9 与 case 5 的本质是相同的。

至此,Intent 的 FLAG_ACTIVITY_NEW_TASK 属性 应该算是讲解清楚了。

我们还可以得出一个有意思结论,那就是 AMS 分配的taskid 是线性递增的,每次开启一个新的task ,taskid 永远都是 +1 的操作。

四、allowTaskReparenting 相关

测试该属性的话,应该先把 FLAG_ACTIVITY_NEW_TASK 属性去掉。

allowTaskReparenting 这个属性指的是一个 Activity 运行时,可以重新选择自己所属的task。基本是在跨app 间调用时,我们在上面的case 8 的基础上,对 Activity 做如下修改

// 将 allowTaskReparenting 设置为 true
<activity android:name=".Main2Activity"
            android:allowTaskReparenting="true"> 
            <intent-filter>
                <action android:name="xxx.lzq"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
case 10: taskReparenting 的时机:

当 A 启动 B 时,这时虽然是在两个进程中的,但其归属的task 是同一个,这时我们回到后台,在桌面点击 B 的应用图标,我们会发现 log 日志如下:
其中 MyApplication 代表 app1,MyApplication2代表 app2。

D/MyApplication: onActivityResumed+MainActivity####taskid = 83
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 83
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 84
case 11: 假如 app2 之前启动过,即app2 所归属的task 已经创建,这时我们再完全重复以上步骤,

log 日志如下:

D/MyApplication2: onActivityResumed+MainActivity####taskid = 86
D/MyApplication: onActivityResumed+MainActivity####taskid = 87
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 87
D/MyApplication2: onActivityResumed+Main2Activity####taskid = 86

此 case 正好验证之前的解析规则,若 Activity taskAffinity指定的task 已经存在,是会复用之前的task,而不会再重新创建一个新的task。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,478评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,825评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,482评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,726评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,633评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,018评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,168评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,320评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,264评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,288评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,995评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,587评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,909评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,284评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,862评论 2 339