站在巨人的肩膀上
Android
总结篇系列:Activity Intent Flags
及Task
相关属性Android
中的Affinity
(各种Intent Flag
以及Activity manifest
特性讲解)ActivityRecord、TaskRecord、ActivityStack
理解 + 总结
- 结论:
如果
Activity
的launchMode
是standard
或singleTop
,那么taskAffinity
设置无效,该Activity
会跟随启动它的Activity
一致的affinity
准备条件: ActivityA: android:launchMode="standard" android:taskAffinity="hello.world" ActivityB: android:launchMode="standard" android:taskAffinity="hello.everyone" ActivityB: android:launchMode="singleTop" android:taskAffinity="hello.everybody" 步骤: 打开ActivityA -> startActivity到ActivityB -> startActivity到ActivityC 结果:(adb shell dumpsys activity) Stack #40: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{fae42ac #403 A=hello.world U=0 StackId=40 sz=3} Run #2: ActivityRecord{d2989ab u0 com.example.hurshi.app_a/.AppA_ActivityC t403} Run #1: ActivityRecord{62cf49f u0 com.example.hurshi.app_a/.AppA_ActivityB t403} Run #0: ActivityRecord{93b3122 u0 com.example.hurshi.app_a/.AppA_ActivityA t403}
由上述实验可知,虽然
ActivityB
设置了taskAffinity
为hello.everyone
,但它还是放在和ActivityA
一致的hello.world
的task
中,说明在上述情况中,设置taskAffinity
无效.ActivityC
同理.
- 结论:
taskAffinity
并不是task
的唯一编号,允许不同task
拥有相同的taskAffinity
准备条件: ActivityA: android:launchMode="singleInstance" android:taskAffinity="hello.world" ActivityB: android:launchMode="singleInstance" android:taskAffinity="hello.world" 步骤: 打开ActivityA -> startActivity到ActivityB 结果: Stack #12: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{783509b #348 A=hello.world U=0 StackId=12 sz=1} Run #0: ActivityRecord{eeea074 u0 com.example.hurshi.app_a/.AppA_ActivityB t348} Stack #11: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{85abc38 #347 A=hello.world U=0 StackId=11 sz=1} Run #0: ActivityRecord{4f6d2db u0 com.example.hurshi.app_a/.AppA_ActivityA t347}
由上述
ActivityA
,ActivityB
可以看出,他们的taskAffinity
是一致的,但是它们的stackId
是不一致的,由此可知:taskAffinity
并不是task
的唯一编号,允许不同task
拥有相同的taskAffinity
- 结论:
当
luanchMode
为singleTask
或者设置Intent.FLAG_ACTIVITY_NEW_TASK
的时候,系统会寻找新的task
来存放目标Activity
,寻找是依据目标Activity
的taskAffinity
属性进行匹配,找不到就新建task
然后放入.如果只设置了
singleTask
或者Intent.FLAG_ACTIVITY_NEW_TASK
,没有设置taskAffinity
,那么该Activity
会沿用Application
的taskAffinity
,而Application
的默认taskAffinity
是包名准备条件: Application: android:taskAffinity="com.application" ActivityA: android:launchMode="standard" android:taskAffinity="hello.world" ActivityB: android:launchMode="singleTask" android:taskAffinity="hello.everyone" 步骤: 打开ActivityA -> startActivity到ActivityB 结果: Stack #38: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{7ff1d1c #401 A=com.application U=0 StackId=38 sz=1} Run #0: ActivityRecord{ecb9efb u0 com.example.hurshi.app_a/.AppA_ActivityB t401} Stack #37: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{2261d25 #400 A=hello.world U=0 StackId=37 sz=1} Run #0: ActivityRecord{4b36f0f u0 com.example.hurshi.app_a/.AppA_ActivityA t400}
- 结论:
在如上结论的基础上,新的
Activity
设置singleTask
后,并不一定会添加到已存在的相同taskAffinity
的task
中,如果相同taskAffinity
的task
是singleInstance
的,那么会新建同名taskAffinity
的task
,然后放入.准备条件: ActivityA: android:launchMode="standard" android:taskAffinity="hello.world" ActivityB: android:launchMode="singleInstance" android:taskAffinity="hello.everyone" ActivityC: android:launchMode="singleTask" android:taskAffinity="hello.everyone" 步骤: 打开ActivityA -> startActivity到ActivityB -> startActivity到ActivityC 结果: Stack #17: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{a26014f #353 A=hello.everyone U=0 StackId=17 sz=1} Run #0: ActivityRecord{358157e u0 com.example.hurshi.app_a/.AppA_ActivityC t353} Stack #16: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{6c18ba #352 A=hello.everyone U=0 StackId=16 sz=1} Run #0: ActivityRecord{68f9e46 u0 com.example.hurshi.app_a/.AppA_ActivityB t352} Stack #15: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{8aed0dc #351 A=hello.world U=0 StackId=15 sz=1} Run #0: ActivityRecord{a37e4a8 u0 com.example.hurshi.app_a/.AppA_ActivityA t351}
由上述可知,
ActivityC
的taskAffinity
虽然和ActivityB
一致,但是因为ActivityB
是singleInstance
,所以ActivityC
添加不到ActivityB
所在的task
中,ActivityC
只能新建一个taskAffinity
也是hello.every
的不同的task
.
什么时候会将目标
Activity
放置到新task
中?- 目标
Activity
的launchMode
设置为singleInstance
的时候. - 目标
Activity
的launchMode
设置为singleTask
,同时设置目标Activity
的taskAffinity
不同于启动它的Activity
- 欢迎补充……
- 目标
launchMode
和Intent Flag
-
singleTop
=FLAG_ACTIVITY_SINGLE_TOP
-
singleTask
=FLAG_ACTIVITY_CLEAR_TOP
+FLAG_ACTIVITY_SINGLE_TOP
-
android:noHistory
错误理解: 具有此属性标识的
Activity
当导航到其他Activity
上时,Activity
栈将不记录其自身. — ❌正确理解: 当当前
Activity
标记为noHistory
时,跳转到其他Activity时,当前Activity
被标记为finishing
,并不会马上调用onDestory
方法,它会在合适的时候调用onDestory
.✅上面”合适的时候”有:当这个
Activity
再次回到前台时,用户点击”Home”键时……欢迎补充,欢迎打脸所以: 标记
noHistory
的Activity
很有可能会导致回收不及时而引起内存问题. 👈👈👈准备条件: ActivityA: ActivityB: android:noHistory="true" ActivityC: 步骤1: 打开ActivityA -> startActivity到ActivityB -> startActivity到ActivityC 结果1: Stack #54: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{26b634f #418 A=com.application U=0 StackId=54 sz=3} Run #2: ActivityRecord{444fa10 u0 com.example.hurshi.app_a/.AppA_ActivityC t418} //最后的 "f" 标记表示 "finishing" Run #1: ActivityRecord{5c65974 u0 com.example.hurshi.app_a/.AppA_ActivityB t418 f} Run #0: ActivityRecord{d4ac684 u0 com.example.hurshi.app_a/.AppA_ActivityA t418} 步骤2: 按 back 键 结果2: Stack #54: type=standard mode=fullscreen Running activities (most recent first): TaskRecord{26b634f #418 A=com.application U=0 StackId=54 sz=1} Run #0: ActivityRecord{d4ac684 u0 com.example.hurshi.app_a/.AppA_ActivityA t418}