目录

导语

一、几个概念

1、概念区分

2、 android:taskAffinity

二、详细描述下这四种启动模式

三、singleTask简单分析

1、实例

2、验证singleTask的几个特点

3、简单总结singleTask的特点

四、singleInstance的简单分析

1、验证singleInstance的几个特点

2、简单总结singleInstance的几个特点

五、总结


导语

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其实都是在这一个任务中的。
一个Activitiy必定在一个任务中进行创建或复用,而一个任务中可以有多个Activity,当然一个任务中也可以有且仅有一个Activitiy。

进程(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键出现的近期的任务列表,当我们点击的时候,仍然可以将该任务切换到前台。所以在打开一个应用的时候,其实就是创建任务或者把之前的任务切换到前台的一个过程。

另外里面分析的不对的地方,也恳请大家指出来。

Android 的singleTask和singleInstance的一点思考相关推荐

  1. 【Android】SingleTask与SingleInstance的区别

    现有2个项目,taskA.taskB.taskA负责调用taskB中指定的界面. taskB中有3个界面,a.b.c,每个界面显示它所在的task id. SingleTask: 其中b界面被声明为S ...

  2. App用户体验的一点思考

    App用户体验的一点思考 最近我在团队中负责TImers4Me这款Android软件的开发.维护和更新,软件每次在市场上的发布都能得到用户一些有价值的反馈,通过收集整理用户们的使用反馈,我们常能看到一 ...

  3. android singleinstance home,Android启动模式之singleinstance的坑

    前言 在实际应用中,使用singleinstance启动模式时,会遇到一些奇奇怪怪的问题.Android有四种启动模式,分别是standard,singleTop,singleTask,singleI ...

  4. Activity之launchMode:singleTop,singleTask与singleInstance

    相关内容,可以参见官方网址: http://developer.android.com/guide/components/tasks-and-back-stack.html 如图所示,如果ABC三个A ...

  5. standard、singleTop、singleTask和singleInstance原理分析

    关键函数入口:startActivityUncheckedLocked   我们知道启动一个Activity有四种方式:standard(标准启动模式).singleTop.singleTask.si ...

  6. android中singleTask的home键的问题

    在Android设计中遇到这样一个问题: Activity A,在中设置它的一个为 AndroidManifest.xml代码 <intent-filter> <action and ...

  7. standard、singleTop、singleTask和singleInstance四种Activity启动模式的理解

    之前自学android的时候,单从视频和书本上对这四种启动模式仅仅有了初步的字面上的理解.最近实战了下,也对这四种启动模式有了比较清晰的概念. 首先说下什么是Activity,按照我的理解,我们在手机 ...

  8. mysql 手动写时间_关于数据库中如何存储时间的一点思考

    1.切记不要用字符串存储日期 我记得我在大学的时候就这样干过,而且现在很多对数据库不太了解的新手也会这样干,可见,这种存储日期的方式的优点还是有的,就是简单直白,容易上手. 但是,这是不正确的做法,主 ...

  9. 对于表列数据类型选择的一点思考

    对于表列数据类型选择的一点思考 简介 SQL Server每个表中各列的数据类型的选择通常显得很简单,但是对于具体数据类型的选择的不同对性能的影响还是略有差别.本篇文章对SQL Server表列数据类 ...

  10. 关于STM32驱动DS1302实时时钟的一点思考

    关于STM32驱动DS1302实时时钟的一点思考 之前用51驱动过DS1302,没用多久就输出了正确的时间.当时以为这块芯片其实没啥,很简单.但是现在用STM32做项目,用到同样的芯片,以为这有何难, ...

最新文章

  1. python如何使用ppip安装xlwt_Python中xlrd和xlwt模块使用方法
  2. python数据分析工资_python3对拉勾数据进行可视化分析的方法详解
  3. $git学习总结系列(4)——gitignore文件
  4. ABAP基础篇-语法-数据类型
  5. 程序员的数学 3 线性代数pdf
  6. 【Linux】下载暂停后如何恢复
  7. 30种大脑训练方法:提高你的注意力(修订本) - 目录
  8. java 数据内地地址_我国大陆居民×××Java验证
  9. 使用SPSS对数据异常值进行探索分析
  10. 留学生交流互动论坛网站
  11. 2022-2023级西安交通大学MBA提前面试(预报名即将开启)6月初
  12. 【工厂扫码打印扫码装箱错误追溯系统】完整案例详解(PythonPyQt 源码Mysql数据库)
  13. 5款考试学习的高效率APP,让你轻松学习一整天!
  14. 嵌入式软件管培生每日总结-第6-7天
  15. cocos2d - JS 物理引擎 - chipmunk
  16. 浙大python习题超详细思路(第二章)
  17. 二叉树的中序遍历,前序遍历,后序遍历
  18. 2021苍穹战队视觉组寒假学习计划--环境配置
  19. 云服务器安装数据库MySQL后,MySQL不能从外部连接的原因及解决
  20. 渭南师范计算机学院男女比例,全国高校男女比例大揭秘!去这些大学怕是要单身四年了...

热门文章

  1. 主引導记录(MBR)
  2. Java中的JUnit单元测试
  3. linux的php探针使用,php探针在Linux下的安装过程分享
  4. 让Office 2003与Office 2010完美共存
  5. 64位计算机可以安装xp,64位xp系统如何安装【图解】
  6. linux系统用虚拟光驱装win7,怎么用虚拟光驱安装系统
  7. 数字通信系统的性能及可靠性
  8. PSP ISO游戏运行必备工具:ISO TOOL 1.970 功能一览图文教程
  9. vs2008 sp1安装时候系统盘空间不够问题,解决方式
  10. matlab雷达噪声模型,雷达信号处理MATLAB仿真.doc