大家好,又见面了,我是你们的朋友全栈君。
目录
导语
Activity的四种启动模式主要有standard、singleTop、singleTask、singleInstance四种。不同的启动模式对该Activity有着不同的启动方式,对应AndroidManifest中的android:launchMode属性。
在刚接触这几个概念的时候,就简单的知道
启动模式 | 简单的最初理解 |
standard | Activity被实例化多次 |
singleTop | 如果在栈顶存在Activitiy实例的话就重用,否则重新创建Activitiy实例 |
singleTask | 如果只要在栈中存在Activitiy实例的话就重用,否则重新创建Activitiy实例 |
singleInstance | 全局只有一个activity实例 |
但是随着最近对于源码和有些知识点的研究,有些疑问就来了:
像什么是栈中和栈顶存在实例?这个栈中和栈顶到底是什么意思?
像singleInstance对应的这个实例,这个全局到底指的范围有多广?到底指的是哪个范围内全局?
为什么standard的Activity启动多次,会在按back键的时候,需要一层一层的退出?
。。。。。
有了这些疑问,我就想着一定要研究一下。
一、几个概念
1、概念区分
概念 | 简单解释 |
任务(Task) |
就是一组Activity的集合。以栈的形式管理开启的activity,开启和关闭activity其实就是在执行压栈和出栈操作。 当不管从Launcher或者其他地方启动应用的时候,会启动应用默认的Activity,这时就会创建或者复用一个任务。默认的之后开启的Activity其实都是在这一个任务中的。 |
进程(Process) | 系统进行资源分配和调度的一个独立单位。不只是程序的代码,还包括当前的活动。打开一个应用,其实就是开启了一个进程,默认情况下,统一应用的所有组件都是在相同的进程中运行的 |
2、 android:taskAffinity
对于Activity所在的任务其实在AndroidManifest对应的android:taskAffinity属性值。
android:taskAffinity表示Activity所在的任务,默认就是包名,若为空字符串,则表示Activity不属于任何Task;相同的taskAffinity的Activity则在同一个任务中。
二、详细描述下这四种启动模式
启动模式 | 在详细点 |
standard | 默认的启动模式。每次启动的Activity都会在任务栈中实例化,在该Activity会在所在的任务栈(这个也就是上面我的第一个疑问:这个栈到底指的是什么:我觉得就可以理解为这个Activity所在的这个任务,即一组Activity的集合,该集合只不过是通过栈进行管理)中存在多个Activity的实例,当返回的时候,需要每个Activity分别出栈(也就解释了为什么standard的Activity启动多次,会在按back键的时候,需要一层一层的退出)。 |
singleTop | 如果在任务栈顶存在Activitiy实例,则通过onNewIntent激活重用;只要不在栈顶存在,则创建Activitiy实例,任务栈中会有多个Activity实例。 |
singleTask |
默认的情况下,如果在任务栈中若不存在Activity实例,创建实例;否则则通onNewIntent激活重用,在重用该实例的时候,会将该实例上的其他activity的实例清除。 在对应的任务栈中有且仅有一个实例。 当然如果和android:taskAffinity配合使用,则可以在开启或者复用另外任务栈中来创建或重用Activity实例。 有该Activity启动的其他Activity默认的都会在该Activity所在的任务栈中,除非去设置了android:taskAffinity或将Activity 的launchMode设置为singleInstance。 |
singleInstance |
在新的任务栈中开启,并且该新的任务中有且仅有这一个Activity实例,若复用Activity实例时,则通过onNewIntent进行激活。 有该Activity启动的其他Activity不会在该Activity所在的任务栈中,可以在已有的任务栈中,也可以在新创建的任务中。 并且该Activity实例是在整个系统中有且仅有一个(就是我疑问的这个全局范围有多广)。 |
standard和singleTop这两种方式,其实很简单,就是在任务栈中根据不同的情况多次实例化Activity。重点分析下singleTask和singleInstance
三、singleTask简单分析
1、实例
应用A:默认启动的Activity为MainActivity,MainActivity来启动launchMode=”singleTask”和不设置android:taskAffinity的FirstActivity
通过getTaskId()来查看MainActivity和FirstActivity的任务id,发现一致
01-15 15:02:22.326 4128-4128/com.j1.task D/TAG: MainActivity get task id = 1000
01-15 15:02:24.077 4128-4128/com.j1.task D/TAG: FirstActivity get task id = 1000
通过adb shell dumpsys activity查看,MainActivity和FirstActivity也的确都是在一个任务栈中。
TaskRecord{af3799f #1000 A=com.j1.task U=0 StackId=1 sz=2}
.......
Hist #1: ActivityRecord{e764b24 u0 com.j1.task/.FirstActivity t1000}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{8b36aec 4128:com.j1.task/u0a87}
Hist #0: ActivityRecord{45274f5 u0 com.j1.task/.MainActivity t1000}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.j1.task/.MainActivity bnds=[230,1238][437,1516] }
ProcessRecord{8b36aec 4128:com.j1.task/u0a87}
这里就有一个疑问
在Google的API文档中说的是:
The system creates a new task and instantiates the activity at the root of the new task.
系统会创建一个新的任务,初始化该Activity实例,将该实例放到新任务栈的栈底。
和刚才输出的结果是相矛盾的。
实际上,在singleTask模式下,系统在启动该Activity的时候,还会受android:taskAffinity这个属性限制。
其实现过程如下:
1)系统在启动singleTask的FirstActivity的时候,会标记为FLAG_ACTIVITY_NEW_TASK
2)检测android:taskAffinity这个属性所在的任务是否存在,若不存在,则新建该任务栈,如果存在该任务栈,则调度到前台
3)在任务栈中查找是否存在FirstActivity实例,如果不存在,则创建FirstActivity实例;若存在,则通过onNewIntent激活。
由于FirstActivity没有设置android:taskAffinity,所以默认的为包名,则就是MainActivity所在的任务栈,所以上面的两个task id为相同的。当设置不同的android:taskAffinity的时,就可以创建新的任务栈了。下面也会通过具体的实例来验证singleTask的这些特点。
2、验证singleTask的几个特点
1)若存在实例,则重用该实例,并会将该任务栈上面的其他Activity实例清除。
继续上面的实例,在FirstActivity上在启动没有设置aunchMode和taskAffinity的SecondActivity
通过getTaskId()来查看三个Activity的task id
01-15 15:24:31.620 5037-5037/? D/TAG: MainActivity get task id = 1005
01-15 15:24:39.860 5037-5037/com.j1.task D/TAG: FirstActivity get task id = 1005
01-15 15:24:45.870 5037-5037/com.j1.task D/TAG: SecondActivity get task id = 1005
通过adb shell dumpsys activity查看,三个Activity在同一个任务栈中。
TaskRecord{2746d98 #1005 A=com.j1.task U=0 StackId=1 sz=3}
.........
Hist #2: ActivityRecord{b429705 u0 com.j1.task/.SecondActivity t1005}
Intent { cmp=com.j1.task/.SecondActivity }
ProcessRecord{8729f1 5176:com.j1.task/u0a87}
Hist #1: ActivityRecord{dabde95 u0 com.j1.task/.FirstActivity t1005}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{8729f1 5176:com.j1.task/u0a87}
Hist #0: ActivityRecord{9a270ad u0 com.j1.task/.MainActivity t1005}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.j1.task/.MainActivity }
ProcessRecord{8729f1 5176:com.j1.task/u0a87}
此时任务栈中依次为: MainActivity(9a270ad)、FirstActivity(dabde95)、SecondActivity(b429705)
现在在SecondActivity中开启FirstActivity,在通过adb shell dumpsys activity查看,发现任务栈中只有 MainActivity(9a270ad)、FirstActivity(dabde95)
TaskRecord{2746d98 #1005 A=com.j1.task U=0 StackId=1 sz=2}
.......
Hist #1: ActivityRecord{dabde95 u0 com.j1.task/.FirstActivity t1005}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{8729f1 5176:com.j1.task/u0a87}
Hist #0: ActivityRecord{9a270ad u0 com.j1.task/.MainActivity t1005}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.j1.task/.MainActivity }
ProcessRecord{8729f1 5176:com.j1.task/u0a87}
我们对比两个FirstActivity红色标记的对应的是同一个实例,同时SecondActivity已经被自动清空了。
2)singleTask和android:taskAffinity巧妙的配合使用
- (1)开启新的任务栈
实例:默认启动的Activity为MainActivity,MainActivity来启动launchMode=”singleTask”和android:taskAffinity=”com.j1.task2″的FirstActivity
还是通过getTaskId()来查看task id,发现两个的任务Id已经不相同
01-15 15:43:29.142 5825-5825/? D/TAG: MainActivity get task id = 1006
01-15 15:43:33.720 5825-5825/com.j1.task D/TAG: FirstActivity get task id = 1007
同样通过adb shell dumpsys activity查看
TaskRecord{5f8ce8c #1007 A=com.j1.task2 U=0 StackId=1 sz=1}
Run #1: ActivityRecord{9a791e9 u0 com.j1.task/.FirstActivity t1007}
TaskRecord{626c9d5 #1006 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{778236f u0 com.j1.task/.MainActivity t1006}
同样发现这里也新建了一个任务。所以当设置 android:taskAffinity的时候,可以在新的任务栈中创建Activity实例
- (2)singleTask的Activity去启动其他Activity,其他Activity会在singleTask的Activity所在的任务栈
接着上面的实例,用FirstActivity去开启SecondActivity
通过getTaskId()发现SecondActivity 和FirstActivity的task id相同,和MainActivity的task id已经不在相同
01-15 15:43:29.142 5825-5825/? D/TAG: MainActivity get task id = 1006
01-15 15:43:33.720 5825-5825/com.j1.task D/TAG: FirstActivity get task id = 1007
01-15 16:10:48.459 5825-5825/com.j1.task D/TAG: SecondActivity get task id = 1007
同样通过adb shell dumpsys activity查看
TaskRecord{5f8ce8c #1007 A=com.j1.task2 U=0 StackId=1 sz=2}
Run #2: ActivityRecord{6819135 u0 com.j1.task/.SecondActivity t1007}
Run #1: ActivityRecord{9a791e9 u0 com.j1.task/.FirstActivity t1007}
TaskRecord{626c9d5 #1006 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{778236f u0 com.j1.task/.MainActivity t1006}
发现由FirstActivity开启的SecondActivity也是在FirstActivity的任务栈中了 。
- (3)复用已存在的任务栈
主要用在不同的应用之间可以将不同的Activity设置为相同的android:taskAffinity。
还是紧接上面的实例,增加第二个应用:该应用中默认启动的为MainActivity1,在MainActivity1中去启动设置launchMode=”singleTask”和android:taskAffinity=”com.j1.task2″的FirstActivity1。
我们先将之前的应用置于后台,打开第二个应用的MainActivity1,然后打开FirstActivity1。
通过getTaskId()发现,FirstActivity1的task id和第一个应用中的FirstActivity是一致的,但和MainActivity1的task id不一致
01-15 16:18:56.792 6890-6890/? D/TAG: MainActivity1 get task id = 1008
01-15 16:21:36.266 6890-6890/com.j1.task3 D/TAG: FirstActivity1 get task id = 1007
同样通过adb shell dumpsys activity查看
TaskRecord{5f8ce8c #1007 A=com.j1.task2 U=0 StackId=1 sz=3}
.......
Hist #2: ActivityRecord{f468078 u0 com.j1.task3/.FirstActivity1 t1007}
Intent { flg=0x10400000 cmp=com.j1.task3/.FirstActivity1 }
ProcessRecord{5c85437 6890:com.j1.task3/u0a88}
Hist #1: ActivityRecord{6819135 u0 com.j1.task/.SecondActivity t1007}
Intent { cmp=com.j1.task/.SecondActivity }
ProcessRecord{fc105ea 5825:com.j1.task/u0a87}
Hist #0: ActivityRecord{9a791e9 u0 com.j1.task/.FirstActivity t1007}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{fc105ea 5825:com.j1.task/u0a87}
发现FirstActivity1会在FirstActivity所在的任务栈中,复用了FirstActivity的任务栈。并且FirstActivity1所在的进程为5c85437,而FirstActivity所在的进程为fc105ea。
而第二个应用的任务栈只有MainActivity1所在的任务栈。
TaskRecord{78e5d36 #1008 A=com.j1.task3 U=0 StackId=1 sz=1}
.....
Hist #0: ActivityRecord{207eb55 u0 com.j1.task3/.MainActivity1 t1008}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.j1.task3/.MainActivity1 }
ProcessRecord{5c85437 6890:com.j1.task3/u0a88}
同时在第二个应用的FirstActivity1界面按返回键的时候,返回也是第一个应用的SecondActivity的界面,更加证明了:FirstActivity1在复用FirstActivity创建的任务栈。
- (4)任务栈中只存在一个activity实例
上面的(1)其实也验证了任务栈总只有一个实例。
3、简单总结singleTask的特点
1)默认情况下,开启singleTask的Activity并不会创建新任务,要配合android:taskAffinity来决定是否创建新任务。
2)在任务栈中先判断是否有Activity实例,若不存在,则直接在任务栈中创建Activity实例;若存在,则从任务栈中通过onNewIntent()激活该Activity实例,并将该实例上面的其他Activity实例给清空。
3)可以通过android:taskAffinity在另外一个应用中复用任务栈。
4)在Activity实例所在的任务栈中,该实例有且仅有一个。
四、singleInstance的简单分析
1、验证singleInstance的几个特点
1)该Activity在新任务中开启,并且该任务有且仅有该Activity实例
实例:默认启动的Activity为MainActivity,MainActivity来启动launchMode=”singleInstance”和没有设置android:taskAffinity的FirstActivity,同时FirstActivity去开启没有设置launchMode和android:taskAffinity的SecondActivity
通过getTaskId()发现FirstActivity和MainActivity的taskId不一致,并且有FirstActivity开启的SecondActivity也不和FirstActivity的task Id不一致
01-15 16:58:37.714 8107-8107/com.j1.task D/TAG: MainActivity get task id = 1012
01-15 16:58:40.970 8107-8107/com.j1.task D/TAG: FirstActivity get task id = 1013
01-15 16:58:50.774 8107-8107/com.j1.task D/TAG: SecondActivity get task id = 1012
同样通过adb shell dumpsys activity查看
TaskRecord{67aec12 #1012 A=com.j1.task U=0 StackId=1 sz=2}
......
Hist #1: ActivityRecord{58328d0 u0 com.j1.task/.SecondActivity t1012}
Intent { flg=0x10400000 cmp=com.j1.task/.SecondActivity }
ProcessRecord{5adbde0 8107:com.j1.task/u0a87}
Hist #0: ActivityRecord{ed15ad1 u0 com.j1.task/.MainActivity t1012}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.j1.task/.MainActivity bnds=[643,245][849,523] }
ProcessRecord{5adbde0 8107:com.j1.task/u0a87}
TaskRecord{6144899 #1013 A=com.j1.task U=0 StackId=1 sz=1}
......
Hist #0: ActivityRecord{c4d910f u0 com.j1.task/.FirstActivity t1013}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{5adbde0 8107:com.j1.task/u0a87}
可以看到FirstActivity会重新创建一个新的任务栈,并且有它开启的SecondActivity也不会在该任务栈中创建。
这里的有且仅有还要在验证下。假设我们将FirstActivity的android:taskAffinity设置为”com.j1.task4″,SecondActivity的launchMode=”singleTask”和android:taskAffinity设置为”com.j1.task4″。
通过查看task id 发现,FirstActivity和SecondActivity的taskid是不一致的
01-16 14:30:48.932 11643-11643/? D/TAG: MainActivity get task id = 1057
01-16 14:31:03.215 11643-11643/com.j1.task D/TAG: FirstActivity get task id = 1059
01-16 14:31:08.614 11643-11643/com.j1.task D/TAG: SecondActivity get task id = 1058
同样通过adb shell dumpsys activity查看 ,虽然名字都是”com.j1.task4″,但是仍然是不同的任务栈。
TaskRecord{236bd7a #1058 A=com.j1.task4 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{1f3d56f u0 com.j1.task/.SecondActivity t1058}
TaskRecord{f6fb721 #1059 A=com.j1.task4 U=0 StackId=1 sz=1}
Run #1: ActivityRecord{8e51ef3 u0 com.j1.task/.FirstActivity t1059}
TaskRecord{566092b #1057 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{53f99eb u0 com.j1.task/.MainActivity t1057}
所以singleInstance的Activity所在的任务栈中有且仅有该Activity实例一个。
2)系统全局只有一个Activity实例
实例:给上述的提到的应用的FirstActivity,增加一个intentFilter,在第二个应用中通过隐式打开FirstActivity
第一个APP仍然直到打开SecondActivity,查看getTaskId()
01-15 17:09:10.591 8702-8702/? D/TAG: MainActivity get task id = 1014
01-15 17:09:48.447 8702-8702/com.j1.task D/TAG: FirstActivity get task id = 1015
01-15 17:10:05.749 8702-8702/com.j1.task D/TAG: SecondActivity get task id = 1014
同样通过adb shell dumpsys activity查看
TaskRecord{ba4968f #1014 A=com.j1.task U=0 StackId=1 sz=2}
.....
Hist #1: ActivityRecord{5f6eaa7 u0 com.j1.task/.SecondActivity t1014}
Intent { flg=0x10400000 cmp=com.j1.task/.SecondActivity }
ProcessRecord{c8ddd1c 8702:com.j1.task/u0a87}
Hist #0: ActivityRecord{d2fad2b u0 com.j1.task/.MainActivity t1014}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.j1.task/.MainActivity }
ProcessRecord{c8ddd1c 8702:com.j1.task/u0a87}
TaskRecord{16ddd25 #1015 A=com.j1.task U=0 StackId=1 sz=1}
......
Hist #0: ActivityRecord{7708492 u0 com.j1.task/.FirstActivity t1015}
Intent { flg=0x10000000 cmp=com.j1.task/.FirstActivity }
ProcessRecord{c8ddd1c 8702:com.j1.task/u0a87}
此时的 FirstActivity的AcitivityRecord为7708492,t1015 。
打开第二个应用,在MainActivity通过隐式打开FirstActivity
查看getTaskId(),第二个应用的只有该输出
01-15 17:13:52.167 8897-8897/com.j1.task3 D/TAG: MainActivity get task id = 1016
同样通过adb shell dumpsys activity查看
TaskRecord{16ddd25 #1015 A=com.j1.task U=0 StackId=1 sz=1}
Run #3: ActivityRecord{7708492 u0 com.j1.task/.FirstActivity t1015}
TaskRecord{cbd269a #1016 A=com.j1.task3 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{c3ca76e u0 com.j1.task3/.MainActivity1 t1016}
TaskRecord{ba4968f #1014 A=com.j1.task U=0 StackId=1 sz=2}
Run #1: ActivityRecord{5f6eaa7 u0 com.j1.task/.SecondActivity t1014}
Run #0: ActivityRecord{d2fad2b u0 com.j1.task/.MainActivity t1014}
此时FirstActivity的AcitivityRecord仍为7708492,任务栈id为1015 。这说明singleInstance的activity实例整个系统中有且仅有一个。
3)singleInstance的activity在启动其他Activity时,其他Activity可以新创建一个任务栈,也可以在已有的任务栈中。
上述的第一个例子中可以看出,如果被singleInstance的activity开启的Activity,如果不设置android:taskAffinity,则会在默认的任务栈中创建实例。
紧接着1)提到的例子来继续,将SecondActivity设置成android:taskAffinity=”com.j1.task2″。
通过getTaskId()发现,和1)不同的是,此时SecondActivity已经和MainActivity的task id不在相同。
01-16 10:22:54.527 3904-3904/com.j1.task D/TAG: MainActivity get task id = 1030
01-16 10:22:56.602 3904-3904/com.j1.task D/TAG: FirstActivity get task id = 1031
01-16 10:23:01.294 3904-3904/com.j1.task D/TAG: SecondActivity get task id = 1032
同样通过adb shell dumpsys activity查看
TaskRecord{faddb55 #1032 A=com.j1.task2 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{221ce9d u0 com.j1.task/.SecondActivity t1032}
TaskRecord{e98796a #1031 A=com.j1.task U=0 StackId=1 sz=1}
Run #1: ActivityRecord{87bb114 u0 com.j1.task/.FirstActivity t1031}
TaskRecord{935741 #1030 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{c2b521c u0 com.j1.task/.MainActivity t1030}
也发现SecondActivity已经在一个新的任务栈中了。不需要设置launchMode就可以创建一个com.j1.task2的新任务栈
那为什么会这样子呢?
1)singleInstance的FirstActivity在开启SecondActivity的时候,系统会给SecondActivity添加FLAG_ACTIVITY_NEW_TASK的标记。
2)检测SecondActivity对应的android:taskAffinity是否存在,默认的为包名,但一定不是singleInstance的FirstActivity的任务栈。若该任务栈已经存在,则在已有的任务栈中查找SecondActivity的实例;若任务栈不存在,则创建新的任务栈。该包名的任务栈是有MainActivity创建的,所以此时任务栈已经存在。
3)有了任务栈之后,是怎么创建SecondActivity实例呢?
- (1)SecondActivity并没有设置android:launchMode,所以直接新建SecondActivity实例。
增加一个实例来验证下。
实例:默认启动的Activity为MainActivity,MainActivity来启动没有设置android:launchMode和android:taskAffinity的SecondActivity,SecondActivity去启动launchMode=”singleInstance”和没有设置android:taskAffinity的FirstActivity,在FirstActivity中再去启动SecondActivity。
第一次打开SecondActivity,查看task id
01-16 10:51:05.164 5279-5279/com.j1.task D/TAG: MainActivity get task id = 1045
01-16 10:51:17.459 5279-5279/com.j1.task D/TAG: SecondActivity get task id = 1045
因为没有设置SecondActivity的android:tlaunchMode和android:taskAffinity,所以和MainActivity的task id一致。
同样通过adb shell dumpsys activity查看
TaskRecord{bae1c1b #1045 A=com.j1.task U=0 StackId=1 sz=2}
Run #1: ActivityRecord{205052d u0 com.j1.task/.SecondActivity t1045}
Run #0: ActivityRecord{64deeec u0 com.j1.task/.MainActivity t1045}
在SecondActivity中打开singleInstance的 FirstActivity,查看task id,发现FirstActivity也的确重新在新的任务栈中开启
01-16 11:36:33.567 5279-5279/com.j1.task D/TAG: FirstActivity get task id = 1046
同样通过adb shell dumpsys activity查看
TaskRecord{a43db91 #1046 A=com.j1.task U=0 StackId=1 sz=1}
Run #2: ActivityRecord{a9f3186 u0 com.j1.task/.FirstActivity t1046}
TaskRecord{bae1c1b #1045 A=com.j1.task U=0 StackId=1 sz=2}
Run #1: ActivityRecord{205052d u0 com.j1.task/.SecondActivity t1045}
Run #0: ActivityRecord{64deeec u0 com.j1.task/.MainActivity t1045}
在FirstActivity中再一次打开SecondActivity,查看task id
01-16 11:38:36.009 5279-5279/com.j1.task D/TAG: SecondActivity get task id = 1045
同样通过adb shell dumpsys activity查看,第二个SecondActivity的ActivityRecord为8c7771a ,第一个SecondActivity的ActivityRecord为205052d,也已经不是同一个实例了
TaskRecord{bae1c1b #1045 A=com.j1.task U=0 StackId=1 sz=3}
Run #3: ActivityRecord{8c7771a u0 com.j1.task/.SecondActivity t1045}
TaskRecord{a43db91 #1046 A=com.j1.task U=0 StackId=1 sz=1}
Run #2: ActivityRecord{a9f3186 u0 com.j1.task/.FirstActivity t1046}
TaskRecord{bae1c1b #1045 A=com.j1.task U=0 StackId=1 sz=3}
Run #1: ActivityRecord{205052d u0 com.j1.task/.SecondActivity t1045}
Run #0: ActivityRecord{64deeec u0 com.j1.task/.MainActivity t1045}
在这个之后,按返回键,此时也只是将1045这个任务栈的Activity依次弹出。
满足下我的好奇心,假设把SecondActivity放到另外一个任务栈中呢?
- (2)有了任务栈之后,SecondActivity的launchMode为singleTask
同样上面的例子,将SecondActivity的launchMode设置为singleTask,android:taskAffinity设置为com.j1.task4。
第一次MainActivity打开SecondActivity,查看task id,SecondActivity和MainActivity的task id是不同的
01-16 13:57:23.292 10618-10618/com.j1.task D/TAG: MainActivity get task id = 1054
01-16 13:57:24.871 10618-10618/com.j1.task D/TAG: SecondActivity get task id = 1055
同样通过adb shell dumpsys activity查看,
TaskRecord{e1af5d3 #1055 A=com.j1.task4 U=0 StackId=1 sz=1}
Run #1: ActivityRecord{25d81f3 u0 com.j1.task/.SecondActivity t1055}
TaskRecord{c932510 #1054 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{739b995 u0 com.j1.task/.MainActivity t1054}
第二次通过FirstActivity打开SecondActivity,查看task id,
01-16 13:58:19.805 10618-10618/com.j1.task D/TAG: FirstActivity get task id = 1056
01-16 13:58:21.777 10618-10618/com.j1.task D/TAG: SecondActivity onNewIntent get task id = 1055
此时SecondActivity已经复用了,不在重新创建,任务id 仍为之前的id
同样通过adb shell dumpsys activity查看,此时SecondActivity的ActivityRecord仍为25d81f3
TaskRecord{e1af5d3 #1055 A=com.j1.task4 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{25d81f3 u0 com.j1.task/.SecondActivity t1055}
TaskRecord{261bc0b #1056 A=com.j1.task U=0 StackId=1 sz=1}
Run #1: ActivityRecord{da3ce7d u0 com.j1.task/.FirstActivity t1056}
TaskRecord{c932510 #1054 A=com.j1.task U=0 StackId=1 sz=1}
Run #0: ActivityRecord{739b995 u0 com.j1.task/.MainActivity t1054}
综述(1)和(2),其实有 singleInstance的Activity的启动其他Activity,除去一定不会在 singleInstance的Activity所在的任务创建实例之外,所在的任务栈和是否创建实例其实仍然取决于launchMode和android:taskAffinity。
2、简单总结singleInstance的几个特点
1)独占一个任务栈,该任务栈中有且仅有该Activity实例
2)整个系统就只有一个实例。
3)被singleIntance的Activity启动的其他Activity,默认的在包名的任务栈中,如果配合android:taskAffinity,也可以新的任务栈中创建的实例。
4)被singleIntance的Activity启动的其他Activity,一定不在singleInstance的Activity所在的栈中,其他Activity的实例的创建和使用取决于该Activity设置的launchMode和android:taskAffinity
五、总结
经过这些分析之后,感觉自己之前有些模棱两可的知识点逐渐清晰起来。系统通过栈的形式管理了一系列的Activity的集合,也就是我们所说的任务栈。
1)当启动模式为standard和singleTop的时候,系统只会在同一任务中对Activity进行创建或复用;
2)当启动模式为singleTask的时候,系统首先会检测该Activity对应的android:taskAffinity任务栈是否存在,若存在,则将该任务切换到前台重用该任务,然后在该任务中查找实例;否则重新创建任务
3)当启动模式为singleInstance的时候,系统首先会检测该Activity实例是否存在,若存在,则将相应的任务切换到前台,重用该实例,否则创建新任务,在新的任务中创建实例。
另外我们平时按home键,也就是将前台任务切换到后台,并且在有些手机上长按home键出现的近期的任务列表,当我们点击的时候,仍然可以将该任务切换到前台。所以在打开一个应用的时候,其实就是创建任务或者把之前的任务切换到前台的一个过程。
另外里面分析的不对的地方,也恳请大家指出来。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153262.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...