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

Android 的singleTask和singleInstance的一点思考[通俗易懂]目录导语一、几个概念1、概念区分2、android:taskAffinity二、详细描述下这四种启动模式三、singleTask简单分析1、实例2、验证singleTask的几个特点3、简单总结singleTask的特点四、singleInstance的简单分析1、验证singleInstance的几个特点2、简单总结singleInstance的…

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

目录

导语

一、几个概念

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

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

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 窗体在任务栏显示 MFC「建议收藏」

    窗体在任务栏显示 MFC「建议收藏」在窗体初始里面加入代码:ModifyStyleEx(0, WS_EX_APPWINDOW);

  • 前端低代码调研与总结

    近些年来,低代码的概念逐渐流行了起来,而低代码产品也越来越多的出现在我们的身边。低代码可以叫做可视化搭建,或者叫效能工具等等。像国外的Mendix,国内的宜搭、苍穹、简道云、amis等等。基于这种新型的开发方式,图形化的拖拉拽配置界面,并兼容了自定义的组件、代码扩展,确实在B端后台管理类网站建设中很大程度上的提升了效率。低代码平台能够高效且便捷,成本又低。就应用领域来讲已经很广泛了,例如营销领域,各种页面生产工具,非冰,乐高,宜搭,鲁班。还有电商类的公司都会给商家提供一个类似店铺装修的工具,小程序生产工具

  • Python Selenium库的使用「建议收藏」

    (一)Selenium基础入门教程:Selenium官网教程1.Selenium简介Selenium是一个用于测试网站的自动化测试工具,支持各种浏览器包括Chrome、Firefox、Safari等主流界面浏览器,同时也支持phantomJS无界面浏览器。2.支持多种操作系统如Windows、Linux、IOS、Android等。3.安装Selenium…

  • Qt的下载安装全教程

    Qt的下载安装全教程Qt的安装及环境配置

  • nginx路径匹配_url路径匹配

    nginx路径匹配_url路径匹配一、前言一般我们经常在访问网站时,通常会遇到输入某个页面的网址时,出现路由的转发,重定向等。可能访问的是一个网址,出来的时候就显示的是另外的地址。这种情况下,通常属于nginx的页面跳转。二、Nginx可提供的服务类型nginx做请求代理,提供多种服务1、php搭建的网站2、hexo创建的博客系统3、spring-boot&tomcat搭建的后台4、静态网页三、location匹配规则1、语法location可以把不同方式的请求,定位到不同的处理方式上.location

    2022年10月18日
  • cortex m3堆栈_arm m0 内核

    cortex m3堆栈_arm m0 内核CortexM3Bit-banding简介分类: ARM MCU2012-06-1914:30 1369人阅读 评论(0) 收藏 举报存储byte语言iocbit-band是Cortex-M3内核中针对某一段区域进行位和字映射的机制,对于位操作,如IO控制LED,相比传递的C语言的位操作,提供了很大的方便.bit-band区域将存储器别名区(bit-ba

    2022年10月13日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号