前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 的singleTask和singleInstance的一点思考[通俗易懂]

Android 的singleTask和singleInstance的一点思考[通俗易懂]

作者头像
全栈程序员站长
发布2022-09-13 11:22:27
4.7K0
发布2022-09-13 11:22:27
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

目录

导语

一、几个概念

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也的确都是在一个任务栈中。

代码语言:javascript
复制
 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在同一个任务栈中。

代码语言:javascript
复制
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)

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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所在的任务栈。

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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″,但是仍然是不同的任务栈。

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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查看

代码语言:javascript
复制
 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查看

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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,也已经不是同一个实例了

代码语言:javascript
复制
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查看,

代码语言:javascript
复制
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

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

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

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153262.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • 一、几个概念
    • 1、概念区分
      • 2、 android:taskAffinity
      • 二、详细描述下这四种启动模式
      • 三、singleTask简单分析
        • 1、实例
          • 2、验证singleTask的几个特点
            • 3、简单总结singleTask的特点
            • 四、singleInstance的简单分析
              • 1、验证singleInstance的几个特点
                • 2、简单总结singleInstance的几个特点
                • 五、总结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档