背景
出现一个很神奇的问题,集成了一个library依赖后,每启动一个FLAG_ACTIVITY_NEW_TASK标志位的Activity就会在任务管理器中多一个"应用"。
如果去除这个library依赖,则无论启动多少个带FLAG_ACTIVITY_NEW_TASK标志位的Activity,任务管理器中永远都只有这一个"应用"。
重现步骤
我们依赖了该library库,然后启动了3个带FLAG_ACTIVITY_NEW_TASK标志位的activity,MainActivity->SecondActivity->ThirdActivity
- val intent = Intent(MainActivity@ this, SecondActivity::class.java)
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- startActivity(intent)
复制代码 我们打开任务管理器,可以看到如下效果
如果,我们去除该library的依赖,打开任务管理器,就只会有一个"应用"。
或者去除启动Activity时的FLAG_ACTIVITY_NEW_TASK标志,也只会有一个应用。
原因
后来,排查后,发现和taskAffinity有关。
原来,在该library中,我们在AndroidManifest.xml的Application节点 添加了一个android:taskAffinity="",导致了这个问题。
去掉这个值就不会有这个问题了。
taskAffinity
taskAffinity我们平时很少去用它,它的作用是什么呢 ?
查阅了资料可知
是用于在启动activity时,指定activity放入哪个task (指定想要的任务栈)
官网文档上关于taskAffinity的说明 : https://developer.android.google.cn/guide/topics/manifest/activity-element#lmode
我们来做下试验
试验一
我们保留android:taskAffinity="",启动了3个带FLAG_ACTIVITY_NEW_TASK标志位的activity,MainActivity->SecondActivity->ThirdActivity,可以看到任务管理器里有3个"应用"
我们使用adb命令,查看下当前Activity栈的信息
- adb shell dumpsys activity activities
复制代码 我们搜索Stack #,可以看到如下信息
- Stack #384: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mLastPausedActivity: ActivityRecord{18aa8f u0 com.heiko.mytest0614/.ThirdActivity t384}
- * Task{812611c #384 visible=true type=standard mode=fullscreen translucent=true I=com.heiko.mytest0614/.ThirdActivity U=0 StackId=384 sz=1}
- ...省略...
- taskAffinity=null
- ...省略...
- Stack #383: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mLastPausedActivity: ActivityRecord{84c8851 u0 com.heiko.mytest0614/.SecondActivity t383}
- * Task{9c4e8b6 #383 visible=true type=standard mode=fullscreen translucent=true I=com.heiko.mytest0614/.SecondActivity U=0 StackId=383 sz=1}
- ...省略...
- taskAffinity=null
- ...省略...
- Stack #382: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mLastPausedActivity: ActivityRecord{c88411e u0 com.heiko.mytest0614/.MainActivity t382}
- * Task{50f0dff #382 visible=true type=standard mode=fullscreen translucent=true I=com.heiko.mytest0614/.MainActivity U=0 StackId=382 sz=1}
- ...省略...
- taskAffinity=null
- ...省略...
复制代码 com.heiko.mytestApp项目,拥有3个任务栈,且taskAffinity都是null。
试验二
我们去除android:taskAffinity="",启动了3个带FLAG_ACTIVITY_NEW_TASK标志位的activity,MainActivity->SecondActivity->ThirdActivity,可以看到任务管理器里有1个"应用"
我们使用adb命令,查看下当前Activity栈的信息
- adb shell dumpsys activity activities
复制代码 我们搜索Stack #,可以看到如下信息
- ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
- Display #0 (activities from top to bottom):
- Stack #424: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mResumedActivity: ActivityRecord{66c8f u0 com.heiko.mytest0614/.ThirdActivity t424}
- mLastPausedActivity: ActivityRecord{66c8f u0 com.heiko.mytest0614/.ThirdActivity t424}
- * Task{813f21d #424 visible=true type=standard mode=fullscreen translucent=true A=10314:com.heiko.mytest0614 U=0 StackId=424 sz=3}
- ...省略
- supportsSplitScreenWindowingMode=true lastActiveTime=1806671486 (inactive for 7s)
- pcFlags 0 * Hist #2: ActivityRecord{66c8f u0 com.heiko.mytest0614/.ThirdActivity t424}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
- * Hist #1: ActivityRecord{7a80a7 u0 com.heiko.mytest0614/.SecondActivity t424}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
- * Hist #0: ActivityRecord{870bb65 u0 com.heiko.mytest0614/.MainActivity t424}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
复制代码 com.heiko.mytestApp项目,拥有1个任务栈,这个栈里有三个ActivityRecord,且taskAffinity都是10314:com.heiko.mytest0614
试验三
我们去除android:taskAffinity="",ThirdActivity的taskAffinity设置为com.heiko.third,启动了3个带FLAG_ACTIVITY_NEW_TASK标志位的activity,MainActivity->SecondActivity->ThirdActivity,可以看到任务管理器里有2个"应用"
我们使用adb命令,查看下当前Activity栈的信息
- adb shell dumpsys activity activities
复制代码 我们搜索Stack #,可以看到如下信息
- ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
- Display #0 (activities from top to bottom):
- Stack #437: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mResumedActivity: ActivityRecord{2d1e033 u0 com.heiko.mytest0614/.ThirdActivity t437}
- * Task{1e2ff0 #437 visible=true type=standard mode=fullscreen translucent=true A=10314:com.heiko.third U=0 StackId=437 sz=1}
- ...省略...
- supportsSplitScreenWindowingMode=true lastActiveTime=1807455552 (inactive for 2s)
- pcFlags 0 * Hist #0: ActivityRecord{2d1e033 u0 com.heiko.mytest0614/.ThirdActivity t437}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.third
- ...省略...
- Stack #436: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mLastPausedActivity: ActivityRecord{2197e45 u0 com.heiko.mytest0614/.SecondActivity t436}
- * Task{2384575 #436 visible=true type=standard mode=fullscreen translucent=true A=10314:com.heiko.mytest0614 U=0 StackId=436 sz=2}
- ...省略...
- supportsSplitScreenWindowingMode=true lastActiveTime=1807455438 (inactive for 2s)
- pcFlags 0 * Hist #1: ActivityRecord{2197e45 u0 com.heiko.mytest0614/.SecondActivity t436}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
- * Hist #0: ActivityRecord{bfa74ac u0 com.heiko.mytest0614/.MainActivity t436}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
复制代码 com.heiko.mytestApp项目,拥有2个任务栈。
Stack #437任务栈里有一个ActivityRecord,taskAffinity为10314:com.heiko.third,
Stack #436任务栈里有两个ActivityRecord,taskAffinity为10314:com.heiko.mytest0614
试验四
我们去除android:taskAffinity="",ThirdActivity的launchMode设置为singleInstance,启动了3个带FLAG_ACTIVITY_NEW_TASK标志位的activity,MainActivity->SecondActivity->ThirdActivity,可以看到任务管理器里有1个"应用"
我们使用adb命令,查看下当前Activity栈的信息
- adb shell dumpsys activity activities
复制代码 我们搜索Stack #,可以看到如下信息
- ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
- Display #0 (activities from top to bottom):
- Stack #434: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mResumedActivity: ActivityRecord{e1a6f04 u0 com.heiko.mytest0614/.ThirdActivity t434}
- * Task{2caced #434 visible=true type=standard mode=fullscreen translucent=true A=10314:com.heiko.mytest0614 U=0 StackId=434 sz=1}
- ...省略...
- pcFlags 0 * Hist #0: ActivityRecord{e1a6f04 u0 com.heiko.mytest0614/.ThirdActivity t434}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
-
-
- Stack #433: type=standard mode=fullscreen
- isSleeping=false
- mBounds=Rect(0, 0 - 0, 0)
- mLastPausedActivity: ActivityRecord{8551b41 u0 com.heiko.mytest0614/.SecondActivity t433}
- * Task{4450b31 #433 visible=true type=standard mode=fullscreen translucent=true A=10314:com.heiko.mytest0614 U=0 StackId=433 sz=2}
- ...省略...
- supportsSplitScreenWindowingMode=true lastActiveTime=1807157149 (inactive for 2s)
- pcFlags 0 * Hist #1: ActivityRecord{8551b41 u0 com.heiko.mytest0614/.SecondActivity t433}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
- * Hist #0: ActivityRecord{ec9ff65 u0 com.heiko.mytest0614/.MainActivity t433}
- packageName=com.heiko.mytest0614 processName=com.heiko.mytest0614
- ...省略...
- taskAffinity=10314:com.heiko.mytest0614
- ...省略...
复制代码 com.heiko.mytestApp项目,拥有2个Activity栈,Stack #433任务栈里有两个ActivityRecord,Stack #434栈中有一个ActivityRecord,且taskAffinity都是10314:com.heiko.mytest0614
小结
- taskAffinity的不同,直观的表现是在任务管理器里,以不同的"应用"来体现
- 微信的每一个小程序,都在任务管理器里单独显示,也是用到了taskAffinity
- taskAffinity一样的Activity具有同一任务 (从用户的角度来看,则是归属同一"应用")
- 默认情况下,应用中的所有 Activity的taskAffinity 都一样,为应用的包名
- 如要要指定 Activity 与任何任务都不一样,需将其设置为空字符串
- 不仅可以给同一个应用的不同activity设置不同的affinity,也可以给不同应用的activity设置相同的affinity,使它们在用户角度看来好像属于同一个应用
- 当启动模式设置为 standard 或 singleTop 时,taskAffinity是不起作用的,待启动的 Activity 会跟随 源Activity 的任务栈,即使你显式声明了不一样的 taskAffinity
- 当启动模式设置了 singleTask 或者 singleInstance 时,它就会新建任务栈来存储待启动的 Activity 实例
- 除了 singleTask 和 singleInstance 以外,FLAG_ACTIVITY_NEW_TASK 也会使 taskAffinity 生效
在不设置 taskAffinity 的情况下,单独设置 FLAG_ACTIVITY_NEW_TASK 并没有任何意义,不会创建新的任务栈
FLAG_ACTIVITY_NEW_TASK 更被大家所熟知的用法可能是 从非 Activity 环境启动 Activity 。
默认情况下,待启动的 Activity 会进入源 Activity 所在的任务栈中。如果是从 非 Activity 环境启动,例如 Service,Broadcast,Application 等,根本不存在与之对应的任务栈,AMS 无从推断该把 Activity 放入哪个任务栈,就会抛出异常 Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag
对于非 Activity 启动的 Activity需要显示的设置 FLAG_ACTIVITY_NEW_TASK,而singleTask 及 singleInstance 在 AMS 中被预处理后,隐形的设置了 FLAG_ACTIVITY_NEW_TASK,而启动模式是 standard 及 singletTop 的 Activity 不会被设置 FLAG_ACTIVITY_NEW_TASK,除非通过显式的 Intent setFlag() 进行设置。
FLAG_ACTIVITY_NEW_TASK 这个属性更多的关注点是在 Task,可以认为没有设置 FLAG_ACTIVITY_NEW_TASK 的情况下,taskAffinity 可以不考虑。
其他
参考
Android Task 相关
任务栈?返回栈?启动模式?
面试官装x失败之:Activity的启动模式
taskAffinity的使用
Android Developer-Activity
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |