n条用例验证Activity4种启动模式的威力与坑

启动模式的使用场景#

标准模式#

特性:

  • 任何页面,如无必要,默认为标准模式,start启动一次创建一个新的Activity

适合场景:

  • 任何页面

singleTop#

特性:

  • 如果该实例已有,且位于栈顶(是Stack顶部还是TaskRecord顶部?),start启动一次,不会重新创建
  • 如果该实例已有,不位于栈顶(是Stack顶部还是TaskRecord顶部?),start启动一次,会重新创建

适合场景:

  • 消息推送: 在单聊页面点击消息通知重新进入一个新的单聊页面
  • 商品推荐:在A商品详情页面点击运营推荐进入一个新的B商品详情页面

singleTask#

特性:

  • 如果该实例已经存在(存在于同一个TaskRecord的?还是存在于Stack中?)但该实例之上还有别的Activity,start启动一次,不会重新创建,会清除该实例之上的所有Activity(清除Stack中其上面的所有?还是TaskRecord内其上面的所有?)

适合场景:

  • 应用中的主页

singleInstance#

特性:

  • 创建一个新的栈结构,似的Activity存在于新的TaskRecord中
  • 如果ActivityA已经存在,通过start方式启动ActivityA,则不会重新创建ActivityA

适合场景:

  • 适用于于App主业务分开的页面
  • 大型App的设置页面
  • 闹铃App,闹铃提醒页面与闹铃设置页面分离

观察Task#

  1. 标准Activity1 -> 标准Activity2
  2. 标准Activity1 -> SingleTask 标记Activity2
  3. 标准Activity1 -> SingleTask +taskAffinity 标记的Activity2
  4. 标准Activity1 -> SingleTop 标记的Activity2
  5. 标准Activity1 -> SingleInstance 标记的Activity2
  6. 标准Activity1 设置启动方式 Intent.FLAG_ACTIVITY_NEW_TASK-> 标准Activity2
  7. 标准Activity1 设置启动方式 allowTaskReparenting -> 标准Activity2

Task小知识#

  • AMS 分配的taskid 是线性递增的,每次开启一个新的task ,taskid 永远都是 +1 的操作。
  • singleTask也是可以做成singleInstance效果的,只要声明taskAffinity 就可以
  • 即一个 task 中的 Activities 是可以运行在不同的进程中的
  • 一个 Activity 运行时所归属的task,默认是启动它 的那个Activity 所在的 task
  • Android 手机的任务列表就是根据不同 task 弹出的,我们可以根据任务管理器有几个 item 图标,来知道我们开启了几个 task
  • 如果 activity 组件没有声明 taskAffinity 的话,该 activity 的 taskAffinity 属性也是有默认值的。
    • 如果 application 指定了 taskAffinity 值,默认值就是 application 指定的 taskAffinity 值;
    • 如果 application 未指定的话,默认值就是 manifest 中声明的包名(package 对应的字符串)。

研究手段#

  1. adb命令查看Activity信息、Task信息、Stack信息,观察Activity顺序、Task顺序、Stack内Activity与Task的顺序
  2. 设计app,至少包括4个Activity,为Activity设置一种启动模式,单独查看每一种启动模式对Activity展示的影响、Task顺序的影响,研究finsh与moveTaskToBack的对比
  3. 总结启动模式的场景

观察SingleTask#

现在我们手里有三个Activity,Activity1 、Activity2、Activity3,启动顺序如下:

Activity1 -> Activity2

Activity2 -> Activity3

Activity1 、Activity2、Activity3分别进行三次配置,观察每一次的启动结果

配置1:

是标准启动模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<activity
android:name=".MainActivity3"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

配置2:

仅配置启动模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<activity
android:name=".MainActivity3"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

配置3:

启动模式+taskAffinity属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<activity
android:name=".MainActivity3"
android:launchMode="singleTask"
android:taskAffinity="com.shaunsheep.ams.singletask.MainActivity3"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:taskAffinity="com.shaunsheep.ams.singletask.MainActivity2"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity"
android:taskAffinity="com.shaunsheep.ams.singletask.MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

第一种配置Activity的launchMode为标准模式

1个TaskRecord,TaskRecord持有3个ActivityRecord,TaskRecord的taskid为#78

1
2
3
4
5
Running activities (most recent first):
TaskRecord{d10ddfa #78 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #4: ActivityRecord{9c889db u0 com.shaunsheep.ams/.MainActivity3 t78}
Run #3: ActivityRecord{8b97fc7 u0 com.shaunsheep.ams/.MainActivity2 t78}
Run #2: ActivityRecord{d3646df u0 com.shaunsheep.ams/.MainActivity t78}

第二种配置Activity的launchMode为singleTask

1个TaskRecord,TaskRecord持有3个ActivityRecord,TaskRecord的taskid为#77

1
2
3
4
5
Running activities (most recent first):
TaskRecord{f0344a5 #77 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #4: ActivityRecord{6df01e3 u0 com.shaunsheep.ams/.MainActivity3 t77}
Run #3: ActivityRecord{b42be4f u0 com.shaunsheep.ams/.MainActivity2 t77}
Run #2: ActivityRecord{333cc50 u0 com.shaunsheep.ams/.MainActivity t77}

第三种配置Activity的launchMode为singleTask且配置了taskAffinity

3个TaskRecord,每个TaskRecord持有一个ActivityRecord,每个TaskRecord持有一个新的taskid,共有三个taskid分别是#75 #72 #71

1
2
3
4
5
6
7
Running activities (most recent first):
TaskRecord{4b8cad3 #75 A=com.shaunsheep.ams.singletask.MainActivity3 U=0 StackId=1 sz=1}
Run #4: ActivityRecord{76a316b u0 com.shaunsheep.ams/.MainActivity3 t75}
TaskRecord{3e7fa15 #72 A=com.shaunsheep.ams.singletask.MainActivity2 U=0 StackId=1 sz=1}
Run #3: ActivityRecord{f932d92 u0 com.shaunsheep.ams/.MainActivity2 t72}
TaskRecord{936112a #71 A=com.shaunsheep.ams.singletask.MainActivity U=0 StackId=1 sz=1}
Run #2: ActivityRecord{88473fb u0 com.shaunsheep.ams/.MainActivity t71}

为了更清楚的演示Singletask的作用,引入第四种配置,与配置3、配置4比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<activity
android:name=".MainActivity4"
android:exported="true" />
<activity
android:name=".MainActivity3"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

从Activity3 -> Activity4 时

1
2
3
4
5
6
7
Running activities (most recent first):
TaskRecord{3fec5b5 #83 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #4: ActivityRecord{6626c2e u0 com.shaunsheep.ams/.MainActivity4 t83}
Run #3: ActivityRecord{2423d8a u0 com.shaunsheep.ams/.MainActivity3 t83}
Run #2: ActivityRecord{a615701 u0 com.shaunsheep.ams/.MainActivity2 t83}
Run #1: ActivityRecord{746700f u0 com.shaunsheep.ams/.MainActivity t83}

从Activity4 -> Activity2 时

1
2
3
4
5
6
Running activities (most recent first):
TaskRecord{3fec5b5 #83 A=com.shaunsheep.ams U=0 StackId=1 sz=2}
Run #2: ActivityRecord{a615701 u0 com.shaunsheep.ams/.MainActivity2 t83}
Run #1: ActivityRecord{746700f u0 com.shaunsheep.ams/.MainActivity t83}


由配置3与配置2、配置4相比,可以看到Activity仅配置Launchemode属性为SingleTask,是不会新建TaskRecord的;换言之,只有当标记为SingleTask且 标记一个新的taskAffinity值时,才会创建一个TaskRecord;

由配置4与配置2相比,可以看到Activity仅仅配置SingleTask,可以达到的效果是:当一个标记为SingleTask的Activity2被重新启动后,该TaskRecord里面位于Activity2之上的ActivityRecord会被清除;

当没有配置taskAffinity,SingleTask标记的Activity仅拥有清除特性;

当配置taskAffinity,SingleTask标记的Activity才会处于一个新的TaskRecord

引入配置5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<activity
android:name=".MainActivity4"
android:exported="true" />
<activity
android:name=".MainActivity3"
android:launchMode="singleTask"
android:taskAffinity="com.shaunsheep.ams.singletask.MainActivity3"
android:exported="true" />
<activity
android:name=".MainActivity2"
android:taskAffinity="com.shaunsheep.ams.singletask.MainActivity2"
android:launchMode="singleTask"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

从Activity3 -> Activity4 时

1
2
3
4
5
6
7
8
9
10
11
12
Running activities (most recent first):
TaskRecord{7b3783a #86 A=com.shaunsheep.ams.singletask.MainActivity3 U=0 StackId=1 sz=2}
Run #4: ActivityRecord{57405d2 u0 com.shaunsheep.ams/.MainActivity4 t86}
Run #3: ActivityRecord{c785935 u0 com.shaunsheep.ams/.MainActivity3 t86}
TaskRecord{ce80ceb #85 A=com.shaunsheep.ams.singletask.MainActivity2 U=0 StackId=1 sz=1}
Run #2: ActivityRecord{a21fe37 u0 com.shaunsheep.ams/.MainActivity2 t85}
TaskRecord{b7f4a48 #84 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #1: ActivityRecord{a172b4f u0 com.shaunsheep.ams/.MainActivity t84}
TaskRecord{9e28cc #62 A=com.unilife.fridge.haierbase.tft U=0 StackId=1 sz=1}
Run #0: ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}


从Activity4 -> Activity2 时

1
2
3
4
5
6
7
8
9
10
11
12
Running activities (most recent first):
TaskRecord{ce80ceb #85 A=com.shaunsheep.ams.singletask.MainActivity2 U=0 StackId=1 sz=1}
Run #4: ActivityRecord{a21fe37 u0 com.shaunsheep.ams/.MainActivity2 t85}
TaskRecord{7b3783a #86 A=com.shaunsheep.ams.singletask.MainActivity3 U=0 StackId=1 sz=2}
Run #3: ActivityRecord{57405d2 u0 com.shaunsheep.ams/.MainActivity4 t86}
Run #2: ActivityRecord{c785935 u0 com.shaunsheep.ams/.MainActivity3 t86}
TaskRecord{b7f4a48 #84 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #1: ActivityRecord{a172b4f u0 com.shaunsheep.ams/.MainActivity t84}
TaskRecord{9e28cc #62 A=com.unilife.fridge.haierbase.tft U=0 StackId=1 sz=1}
Run #0: ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}


可以看到,当Activity、Activity2、Activity3分别创建了三个TaskRecord时,Activity3启动的Activity4,两者都在TaskId为#85的TaskRecord里。

当Activity4启动标记为SingleTask的Activity2时,Activity2所在的#85 Task上移到Stack顶。

启发,SingleInstance、SingleTop的TaskRecord、ActivityRecord分布关系是怎样的呢?

观察SingleTop#

配置1:引入4个标记为SingleTop的Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<activity
android:name=".singletop.MainActivity4"
android:launchMode="singleTop"
android:exported="true" />
<activity
android:name=".singletop.MainActivity3"
android:launchMode="singleTop"
android:exported="true" />
<activity
android:name=".singletop.MainActivity2"
android:launchMode="singleTop"
android:exported="true" />
<activity
android:name=".singletop.MainActivity"
android:launchMode="singleTop"
android:exported="true" />

栈顶启动一个处于非栈顶的标记为SingleTop 且未创建的Activity

Activity3 -> Activity4时

1
2
3
4
5
6
7
8
9
Running activities (most recent first):
TaskRecord{a809353 #94 A=com.shaunsheep.ams U=0 StackId=1 sz=5}
Run #5: ActivityRecord{fa4458e u0 com.shaunsheep.ams/.singletop.MainActivity4 t94}
Run #4: ActivityRecord{e960865 u0 com.shaunsheep.ams/.singletop.MainActivity3 t94}
Run #3: ActivityRecord{6a2a418 u0 com.shaunsheep.ams/.singletop.MainActivity2 t94}
Run #2: ActivityRecord{6387394 u0 com.shaunsheep.ams/.singletop.MainActivity t94}
Run #1: ActivityRecord{a909021 u0 com.shaunsheep.ams/.LaunchActivity t94}


测试1:从Activity4 -> Activity2 时,Activity2处于非栈顶且已经被创建,TaskRecord会装入一个新的Activity2,此时#94有两个Activity2

1
2
3
4
5
6
7
8
9
Running activities (most recent first):
TaskRecord{a809353 #94 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #6: ActivityRecord{32759ec u0 com.shaunsheep.ams/.singletop.MainActivity2 t94}
Run #5: ActivityRecord{fa4458e u0 com.shaunsheep.ams/.singletop.MainActivity4 t94}
Run #4: ActivityRecord{e960865 u0 com.shaunsheep.ams/.singletop.MainActivity3 t94}
Run #3: ActivityRecord{6a2a418 u0 com.shaunsheep.ams/.singletop.MainActivity2 t94}
Run #2: ActivityRecord{6387394 u0 com.shaunsheep.ams/.singletop.MainActivity t94}
Run #1: ActivityRecord{a909021 u0 com.shaunsheep.ams/.LaunchActivity t94}

测试2:栈顶启动一个处于栈顶的标记为SingleTop的Activity,

Activity3 -> Activity4时

1
2
3
4
5
6
7
8
Running activities (most recent first):
TaskRecord{4cac736 #104 A=com.shaunsheep.ams U=0 StackId=1 sz=5}
Run #5: ActivityRecord{b712b49 u0 com.shaunsheep.ams/.singletop.MainActivity4 t104}
Run #4: ActivityRecord{8a27a95 u0 com.shaunsheep.ams/.singletop.MainActivity3 t104}
Run #3: ActivityRecord{87017a1 u0 com.shaunsheep.ams/.singletop.MainActivity2 t104}
Run #2: ActivityRecord{67f2e6d u0 com.shaunsheep.ams/.singletop.MainActivity t104}
Run #1: ActivityRecord{1cc8763 u0 com.shaunsheep.ams/.LaunchActivity t104}

从Activity4 -> Activity4 时,Activity4已经被创建过,再次启动,因此TaskRecord会重新加载Activity3,并进入onNewIntent方法

1
2
3
4
5
6
7
8
Running activities (most recent first):
TaskRecord{4cac736 #104 A=com.shaunsheep.ams U=0 StackId=1 sz=5}
Run #5: ActivityRecord{b712b49 u0 com.shaunsheep.ams/.singletop.MainActivity4 t104}
Run #4: ActivityRecord{8a27a95 u0 com.shaunsheep.ams/.singletop.MainActivity3 t104}
Run #3: ActivityRecord{87017a1 u0 com.shaunsheep.ams/.singletop.MainActivity2 t104}
Run #2: ActivityRecord{67f2e6d u0 com.shaunsheep.ams/.singletop.MainActivity t104}
Run #1: ActivityRecord{1cc8763 u0 com.shaunsheep.ams/.LaunchActivity t104}

并且Activity4的log得到了打印

1
2
3
4
5
6
7
8
2021-10-09 14:45:43.849 12224-12224/com.shaunsheep.ams E/ycf: onNewIntent

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("ycf","onNewIntent");
}

总结SingleTop的小知识:

  • 由测试1可知,当启动一个未处于栈顶标记为SingleTop的Activity2时,Activity2会重新创建一遍,此时TaskRecord中存在两个Activity2
  • 由测试2可知,当启动一个处于栈顶的标记为SingleTop的Activity4时,Activity4并不会重新创建,而是进入该Activity的onNewIntent方法
  • 由测试1、测试2可知,SingleTop并不会新创建一个TaskRecord,仍然处于创建它的Activity所处的TaskRecord内

观察SingleInstance#

配置1:4个SingleInstance#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<activity
android:name=".singleinstance.MainActivity4"
android:launchMode="singleInstance"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity3"
android:launchMode="singleInstance"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity2"
android:launchMode="singleInstance"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity"
android:launchMode="singleInstance"
android:exported="true" />

Activity3 -> Activity4时

1
2
3
4
5
6
7
8
9
10
Running activities (most recent first):
TaskRecord{ceec50d #110 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #9: ActivityRecord{380cf0a u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t110}
TaskRecord{70c2b67 #109 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #8: ActivityRecord{c7b8b53 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t109}
TaskRecord{3c97bb2 #108 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{1fd4065 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t108}
TaskRecord{e261703 #107 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #6: ActivityRecord{e1b93e7 u0 com.shaunsheep.ams/.singleinstance.MainActivity t107}

Activity4 -> Activity2时

1
2
3
4
5
6
7
8
9
10
11
12
Running activities (most recent first):
TaskRecord{3c97bb2 #108 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #9: ActivityRecord{1fd4065 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t108}
TaskRecord{ceec50d #110 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #8: ActivityRecord{380cf0a u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t110}
TaskRecord{70c2b67 #109 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{c7b8b53 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t109}
TaskRecord{e261703 #107 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #6: ActivityRecord{e1b93e7 u0 com.shaunsheep.ams/.singleinstance.MainActivity t107}
TaskRecord{8ce680 #106 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #5: ActivityRecord{8277ba3 u0 com.shaunsheep.ams/.LaunchActivity t106}

Activity4 -> Activity4时

执行了log

1
2
2021-10-09 16:25:30.499 32395-32395/com.shaunsheep.ams E/ycf: onNewIntent

1
2
3
4
5
6
7
8
9
10
11
12
Running activities (most recent first):
TaskRecord{ceec50d #110 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #9: ActivityRecord{380cf0a u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t110}
TaskRecord{70c2b67 #109 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #8: ActivityRecord{c7b8b53 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t109}
TaskRecord{3c97bb2 #108 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{1fd4065 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t108}
TaskRecord{e261703 #107 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #6: ActivityRecord{e1b93e7 u0 com.shaunsheep.ams/.singleinstance.MainActivity t107}
TaskRecord{8ce680 #106 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #5: ActivityRecord{8277ba3 u0 com.shaunsheep.ams/.LaunchActivity t106}

可以看到,当所有Activity都配置成SingleInstance 时候,

Activity4 在栈顶启动自己,Activity4没有重新创建

Activity4 在栈顶启动了Activity2,Activity2 没有重新创建,Activity2 重新置于栈顶

配置2:1个SingleInstance#

Activity2为singleInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<activity
android:name=".singleinstance.MainActivity4"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity3"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity2"
android:launchMode="singleInstance"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity"
android:exported="true" />

测试0:栈列表

一共有两个TaskRecord,标记启动模式为SingleIntance的Activity2位于Task#135中,Activity1、3、4位于Task#134中

1
2
3
4
5
6
7
8
9
10
Running activities (most recent first):
TaskRecord{9609526 #134 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #9: ActivityRecord{4fbc425 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t134}
Run #8: ActivityRecord{2dffdbb u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t134}
TaskRecord{43e1f14 #135 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{bceb142 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t135}
TaskRecord{9609526 #134 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #6: ActivityRecord{4215219 u0 com.shaunsheep.ams/.singleinstance.MainActivity t134}
Run #5: ActivityRecord{5f3ff00 u0 com.shaunsheep.ams/.LaunchActivity t134}

测试1:启动App,Activity4 -> Activity2时

打印了log

1
2
2021-10-09 16:39:16.192 4704-4704/com.shaunsheep.ams E/ycf: MainActivity2 onNewIntent

栈列表有两个#135 和#134,#135有Activity2,#134有Activity4、Activity3、Activity1、LaunchActivity

1
2
3
4
5
6
7
8
9
Running activities (most recent first):
TaskRecord{43e1f14 #135 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #9: ActivityRecord{bceb142 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t135}
TaskRecord{9609526 #134 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #8: ActivityRecord{4fbc425 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t134}
Run #7: ActivityRecord{2dffdbb u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t134}
Run #6: ActivityRecord{4215219 u0 com.shaunsheep.ams/.singleinstance.MainActivity t134}
Run #5: ActivityRecord{5f3ff00 u0 com.shaunsheep.ams/.LaunchActivity t134}

测试2:重启App,Activity2->Activity3时

有两个Task #136和 #137,#136有Activity1、LaunchActivity和Activity3,#137有Activity2

1
2
3
4
5
6
7
8
9
Running activities (most recent first):
TaskRecord{e558bba #136 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #8: ActivityRecord{9fea423 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t136}
TaskRecord{ab449c8 #137 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{4cbaab5 u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t137}
TaskRecord{e558bba #136 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #6: ActivityRecord{45c62a8 u0 com.shaunsheep.ams/.singleinstance.MainActivity t136}
Run #5: ActivityRecord{e23987e u0 com.shaunsheep.ams/.LaunchActivity t136}

测试3:重新启动App,Activity2->Activity3时,重新刷新一遍栈列表,方便下一轮测试,此时TaskId会自增,不再是原来的#137 和#136,而是#138 和#139

在Activity3按下moveTaskToBack(true);,跳回了Activity2

1
2
3
4
5
6
7
8
Running activities (most recent first):
TaskRecord{717c0c5 #139 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #8: ActivityRecord{1aaf98b u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t139}
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #7: ActivityRecord{d5687b0 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t138}
Run #6: ActivityRecord{7423876 u0 com.shaunsheep.ams/.singleinstance.MainActivity t138}
Run #5: ActivityRecord{6bbfbbb u0 com.shaunsheep.ams/.LaunchActivity t138}

此时再次Activity2->Activity3时,重新创建Activity3,注意此时# 138有两个Activity3

1
2
3
4
5
6
7
8
9
10
Running activities (most recent first):
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #9: ActivityRecord{5e4f6c3 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t138}
TaskRecord{717c0c5 #139 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #8: ActivityRecord{1aaf98b u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t139}
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #7: ActivityRecord{d5687b0 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t138}
Run #6: ActivityRecord{7423876 u0 com.shaunsheep.ams/.singleinstance.MainActivity t138}
Run #5: ActivityRecord{6bbfbbb u0 com.shaunsheep.ams/.LaunchActivity t138}

在第二个Activity3按下finsh或者backPress,直接跳回了第一个Activity3,而非预期的Activity2

1
2
3
4
5
6
7
8
9
Running activities (most recent first):
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #8: ActivityRecord{d5687b0 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t138}
TaskRecord{717c0c5 #139 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{1aaf98b u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t139}
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #6: ActivityRecord{7423876 u0 com.shaunsheep.ams/.singleinstance.MainActivity t138}
Run #5: ActivityRecord{6bbfbbb u0 com.shaunsheep.ams/.LaunchActivity t138}

在第一个Activity3按下finsh或者backPress,直接跳回了Activity1,而非预期的Activity2

1
2
3
4
5
6
7
8
Running activities (most recent first):
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=2}
Run #7: ActivityRecord{7423876 u0 com.shaunsheep.ams/.singleinstance.MainActivity t138}
TaskRecord{717c0c5 #139 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #6: ActivityRecord{1aaf98b u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t139}
TaskRecord{df04ae3 #138 A=com.shaunsheep.ams U=0 StackId=1 sz=2}
Run #5: ActivityRecord{6bbfbbb u0 com.shaunsheep.ams/.LaunchActivity t138}

总结SingleInstance的小知识:

  • 由测试0可知,SingleInstance标记的Activity2,必然会独立存在于一个TaskRecord中,它自己启动的新的Activity3,会存在于默认的Task中,默认的Task是启动Activity2的Activity1所在的TaskRecord

  • 由测试1可知,SingleInstance所标记的Activity,如果是首次创建,一定会新创建一个TaskRecord,并置于其中;已经创建,则会使得TaskRecord置于Stack顶部

  • 由测试2和测试3可知标准Activity 1 -> SingleInstance Activity2 -> 标准Activity 3 ,在Activity3 finsh或backPress会跳入Activity1;在Activity3触发moveTaskToBack会跳入Activity2

  • 根据网络文章如果位于Activity2,按下手机home键,重新进入App后,会显示Activity1,可知SingleInstance标记的Activity也影响home键之后的页面展示

  • 由以上三点,可知SingleInstance标记的Activity会影响finsh、backPress、home三类操作之后的页面展示顺序;

进阶测试——activity回退的小bug:#

继续使用配置2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<activity
android:name=".singleinstance.MainActivity4"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity3"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity2"
android:launchMode="singleInstance"
android:exported="true" />
<activity
android:name=".singleinstance.MainActivity"
android:exported="true" />

AMS体系-奇怪的现象

? 在下文中,将moveTaskToBack简写moveback

几个关键的步骤流

1…4的TaskRecord结果如下:,Task#611 存放Activity1、3、4, Task#612存放Activity2,Task#611在栈顶,此时屏幕上展示的是Activity4,符合TaskRecord中的顺序

1
2
3
4
5
6
7
8
9
10
11
Running activities (most recent first):
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #5: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #4: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #3: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


4..moveback的结果如下:

Task#611 存放Activity1、3、4, Task#612存放Activity2,Task#612在栈顶,此时屏幕上展示的是Activity2,符合TaskRecord中的顺序

思考1Tips:此处产生一个小问题,结果不符合我们期望的顺序——程序只moveback了Activity4,没有moveBack Activity3,为什么moveBack Activity4之后,看不到Activity3而是看到Activity2呢?

1
2
3
4
5
6
7
8
9
10
Running activities (most recent first):
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #5: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=4}
Run #4: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #3: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


2..4的结果如下:

Task#611 存放Activity1、3、4、3、4, Task#612存放Activity2,Task#611在栈顶,此时屏幕上展示的是Activity4,符合TaskRecord中的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
Running activities (most recent first):
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #7: ActivityRecord{4798b46 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #6: ActivityRecord{4e20f6c u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #5: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #4: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #3: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


4…moveBack-2结果如下:与步骤2相比,仅多了1个Activity4、1个Activity3,伴随着思考1,moveBack的特性越发引人关注了

1
2
3
4
5
6
7
8
9
10
11
12
Running activities (most recent first):
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #6: ActivityRecord{4798b46 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #5: ActivityRecord{4e20f6c u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #4: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #3: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


2…3结果如下:

可以看到Task#611有Activity1、3、4、3、4、3,Task#612有Activity2,此时屏幕上看到的是Activity3,符合TaskRecord的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Running activities (most recent first):
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=7}
Run #8: ActivityRecord{7702d48 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #7: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=7}
Run #6: ActivityRecord{4798b46 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #5: ActivityRecord{4e20f6c u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #4: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #3: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


在步骤6我们暂停一下,梳理一下逻辑,在这里我们假定实际开发中有一个需求,退出Activity3,显示启动它的Activity2。我们可以通过哪些方式来实现?最简洁的方式就是finsh 销毁Activity3,那我们来实际操作一下看看结果:

finsh 3结果如下:

可以看到Task#611有Activity1、3、4、3、4,Task#612有Activity2,此时屏幕上看到的是Activity4,非常令人震惊,明明在展示Activity3之前,我们看到的Activity2,为什么Activity3销毁,我们看不到Activity2呢?当然下面的TaskRecord已经给出答案,Activity3销毁之后,默认将与Activity3同一TaskRecord的Activity4顶了上来,这也符合TaskRecord列表显示的数据:

Activity3销毁之后看到的是同一TaskRecord的Activity4 而不是启动Activity3的Activity2

1
2
3
4
5
6
7
8
9
10
11
12
13
Running activities (most recent first):
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #7: ActivityRecord{4798b46 u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
TaskRecord{bf2d0e0 #612 A=com.shaunsheep.ams U=0 StackId=1 sz=1}
Run #6: ActivityRecord{15e944a u0 com.shaunsheep.ams/.singleinstance.MainActivity2 t612}
TaskRecord{f170712 #611 A=com.shaunsheep.ams U=0 StackId=1 sz=6}
Run #5: ActivityRecord{4e20f6c u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #4: ActivityRecord{7517f4d u0 com.shaunsheep.ams/.singleinstance.MainActivity4 t611}
Run #3: ActivityRecord{d1ea723 u0 com.shaunsheep.ams/.singleinstance.MainActivity3 t611}
Run #2: ActivityRecord{fe3edcb u0 com.shaunsheep.ams/.singleinstance.MainActivity t611}
Run #1: ActivityRecord{83513cf u0 com.shaunsheep.ams/.LaunchActivity t611}


位于栈顶的Activity3如果通过moveTaskToBack方式回退,则可以实现Activity3消失、显示Activity2的效果

以上问题引发了思考:

  • startActivity、finsh、moveTaskToBack三者之间有何联系

  • finsh与moveTaskToBack对Activity显示有何区别

finsh与moveTaskToBack的对比:

操作上:

  • 两者都会操作WindowList<E> mChildren中子元素顺序
  • moveToBack是一个移动数组末尾元素至首位的操作
  • finsh是一个移除数组末尾元素的操作

显示上:

  • 两者最终呈现在界面上的效果,都是将当前顶部Activity隐藏
  • 两者最明显的区别是,隐藏顶部Activity之后,操作之后,屏幕锁显示的下一个Activity的区别
    • moveTaskToBack会隐藏当前Activity所在的TaskRecord,展示Stack中的下一个TaskRecord
    • finsh会销毁当前Activity,并展示当前Activity所在的TaskReord中的下一个Activity,而非实际的Stack存储的ActivityRecord顺序

帮助文档#

adb#

查看Window#

adb shell "dumpsys window"

主要关注

  • WINDOW MANAGER ANIMATOR STATE
  • WINDOW MANAGER SESSIONS (dumpsys window sessions)
  • WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
  • WINDOW MANAGER TOKENS (dumpsys window tokens)

截取部分段落

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)
DisplayContentsAnimator #0:
Window #0: WindowStateAnimator{8300f9b com.android.systemui.ImageWallpaper}
Window #1: WindowStateAnimator{e1a0f38 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity}
Window #2: WindowStateAnimator{f0bbb11 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity}
Window #3: WindowStateAnimator{b240476 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity}
Window #4: WindowStateAnimator{f60a77 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity2}
Window #5: WindowStateAnimator{efce6e4 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity3}
Window #6: WindowStateAnimator{85ff74d DockedStackDivider}
Window #7: WindowStateAnimator{c3f202 }
Window #8: WindowStateAnimator{6b6d713 AssistPreviewPanel}
Window #9: WindowStateAnimator{d138d50 StatusBar}


mBulkUpdateParams=0x8 ORIENTATION_CHANGE_COMPLETE

WINDOW MANAGER SESSIONS (dumpsys window sessions)
Session Session{567f3f 9459:u0a10057}:
mNumWindow=3 mCanAddInternalSystemWindow=false mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@241bb49
mPackageName=com.shaunsheep.ams
Session Session{15833c4 622:1000}:
mNumWindow=0 mCanAddInternalSystemWindow=true mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@832c4e
mPackageName=com.shaunsheep.ams
Session Session{337aec5 2545:1000}:
mNumWindow=0 mCanAddInternalSystemWindow=true mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@1add16f
mPackageName=com.unilife.fridge.haierbase.navigation
Session Session{6c2c045 1075:1000}:
mNumWindow=0 mCanAddInternalSystemWindow=true mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@7ac2e7c
mPackageName=com.android.settings
Session Session{851ad14 1300:1000}:
mNumWindow=1 mCanAddInternalSystemWindow=true mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@a61c305
mPackageName=com.example.touchdemo
Session Session{8bd8947 1341:u0a10033}:
mNumWindow=2 mCanAddInternalSystemWindow=false mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@fe9bf5a
mPackageName=com.unilife.fridge.haierbase.tft
Session Session{b4457ef 796:u0a10010}:
mNumWindow=4 mCanAddInternalSystemWindow=true mAppOverlaySurfaces=[] mAlertWindowSurfaces=[] mClientDead=false mSurfaceSession=android.view.SurfaceSession@870158b
mPackageName=com.android.systemui

WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
Display: mDisplayId=0
init=1080x1920 160dpi cur=1080x1920 app=1080x1864 rng=1080x1024-1920x1864
deferred=false mLayoutNeeded=false mTouchExcludeRegion=SkRegion((0,0,1080,1920))

Application tokens in top down Z order:
mStackId=1
mDeferRemoval=false
mFillsParent=true
mBounds=[0,0][1080,1920]
taskId=63
mFillsParent=true
mBounds=[0,0][1080,1920]
mdr=false
appTokens=[AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}, AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}, AppWindowToken{6e77b06 to
ken=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}]
mTempInsetBounds=[0,0][0,0]
Activity #2 AppWindowToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}
windows=[Window{8f48b1d u0 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity3}]
windowType=2 hidden=false hasVisible=true
app=true mVoiceInteraction=false
task={taskId=63 appTokens=[AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}, AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}, AppWind
owToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}] mdr=false}
mFillsParent=true mOrientation=-1
hiddenRequested=false mClientHidden=false reportedDrawn=true reportedVisible=true
mAppStopped=true
mNumInterestingWindows=1 mNumDrawnWindows=1 inPendingTransaction=false allDrawn=true (animator=true)
startingData=null removed=false firstWindowDrawn=true mIsExiting=false
controller=AppWindowContainerController{ token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}} mContainer=AppWindowToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}} mListen
er=ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}
Activity #1 AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}
windows=[Window{574d6a9 u0 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity2}]
windowType=2 hidden=true hasVisible=true
app=true mVoiceInteraction=false
task={taskId=63 appTokens=[AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}, AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}, AppWind
owToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}] mdr=false}
mFillsParent=true mOrientation=-1
hiddenRequested=true mClientHidden=true reportedDrawn=false reportedVisible=false
mAppStopped=true
mNumInterestingWindows=1 mNumDrawnWindows=1 inPendingTransaction=false allDrawn=true (animator=true)
startingData=null removed=false firstWindowDrawn=true mIsExiting=false
controller=AppWindowContainerController{ token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}} mContainer=AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}} mListen
er=ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}
Activity #0 AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}
windows=[Window{b61636a u0 com.shaunsheep.ams/com.shaunsheep.ams.singletask.MainActivity}]
windowType=2 hidden=true hasVisible=true
app=true mVoiceInteraction=false
task={taskId=63 appTokens=[AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}, AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}, AppWind
owToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}] mdr=false}
mFillsParent=true mOrientation=-1
hiddenRequested=true mClientHidden=true reportedDrawn=false reportedVisible=false
mAppStopped=true
mNumInterestingWindows=1 mNumDrawnWindows=1 inPendingTransaction=false allDrawn=true (animator=true)
startingData=null removed=false firstWindowDrawn=true mIsExiting=false
controller=AppWindowContainerController{ token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}} mContainer=AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}} mListener
=ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}
taskId=62
mFillsParent=true
mBounds=[0,0][1080,1920]
mdr=false
appTokens=[AppWindowToken{f92e433 token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}}, AppWindowToken{e23349e token=Token{bd672d9 ActivityRecord{5129
20 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}}]
mTempInsetBounds=[0,0][0,0]
Activity #1 AppWindowToken{e23349e token=Token{bd672d9 ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}}
windows=[Window{e22a411 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity}]
windowType=2 hidden=true hasVisible=true
app=true mVoiceInteraction=false
task={taskId=62 appTokens=[AppWindowToken{f92e433 token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}}, AppWindowToken{e23349e token=Token{bd672d9 A
ctivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}}] mdr=false}
mFillsParent=true mOrientation=-1
hiddenRequested=true mClientHidden=true reportedDrawn=false reportedVisible=false
mAppStopped=true
mNumInterestingWindows=1 mNumDrawnWindows=1 inPendingTransaction=false allDrawn=true (animator=true)
startingData=null removed=false firstWindowDrawn=true mIsExiting=false
controller=AppWindowContainerController{ token=Token{bd672d9 ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}} mContainer=AppWindowToken{e23349e token=Token{bd672d9 Ac
tivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}} mListener=ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSe
tWifiActivity t62}}
Activity #0 AppWindowToken{f92e433 token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}}
windows=[Window{ba965b4 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity}]
windowType=2 hidden=true hasVisible=true
app=true mVoiceInteraction=false
task={taskId=62 appTokens=[AppWindowToken{f92e433 token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}}, AppWindowToken{e23349e token=Token{bd672d9 A
ctivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}}] mdr=false}
mFillsParent=true mOrientation=-1
hiddenRequested=true mClientHidden=true reportedDrawn=false reportedVisible=false
mAppStopped=true
mNumInterestingWindows=1 mNumDrawnWindows=1 inPendingTransaction=false allDrawn=true (animator=true)
startingData=null removed=false firstWindowDrawn=true mIsExiting=false
controller=AppWindowContainerController{ token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}} mContainer=AppWindowToken{f92e433 token=Token{a4766b5 A
ctivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}} mListener=ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUser
ProtocolActivity t62}}
mStackId=0
mDeferRemoval=false
mFillsParent=true
mBounds=[0,0][1080,1920]


DimLayerController
Task=62
dimLayer=shared, animator=null, continueDimming=false
mDimSurface=Surface(name=DimLayerController/Stack=0) mLayer=110999 mAlpha=0.0
mLastBounds=[-270,-480][1350,2400] mBounds=[-270,-480][1350,2400]
Last animation: mDuration=200 mStartTime=34184572 curTime=35019291
mStartAlpha=0.6 mTargetAlpha=0.0
Stack=0
dimLayer=shared, animator=null, continueDimming=false
mDimSurface=Surface(name=DimLayerController/Stack=0) mLayer=110999 mAlpha=0.0
mLastBounds=[-270,-480][1350,2400] mBounds=[-270,-480][1350,2400]
Last animation: mDuration=200 mStartTime=34184572 curTime=35019291
mStartAlpha=0.6 mTargetAlpha=0.0
Task=63
dimLayer=shared, animator=null, continueDimming=false
mDimSurface=Surface(name=DimLayerController/Stack=0) mLayer=110999 mAlpha=0.0
mLastBounds=[-270,-480][1350,2400] mBounds=[-270,-480][1350,2400]
Last animation: mDuration=200 mStartTime=34184572 curTime=35019291
mStartAlpha=0.6 mTargetAlpha=0.0
Stack=1
dimLayer=shared, animator=null, continueDimming=false
mDimSurface=Surface(name=DimLayerController/Stack=0) mLayer=110999 mAlpha=0.0
mLastBounds=[-270,-480][1350,2400] mBounds=[-270,-480][1350,2400]
Last animation: mDuration=200 mStartTime=34184572 curTime=35019291
mStartAlpha=0.6 mTargetAlpha=0.0

WINDOW MANAGER TOKENS (dumpsys window tokens)
All tokens:
Display #0
WindowToken{2cbb668 android.os.BinderProxy@62938f9}
AppWindowToken{4df35c8 token=Token{47c192d ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}}}
AppWindowToken{f92e433 token=Token{a4766b5 ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}}}
WallpaperWindowToken{ec08a81 token=android.os.Binder@178873c}
WindowToken{2f47726 android.os.BinderProxy@2c6f5c2}
WindowToken{bc87f67 android.os.Binder@af389a}
WindowToken{bd9d114 android.os.BinderProxy@b1561e2}
WindowToken{2ea4dbd android.os.BinderProxy@e2e8034}
AppWindowToken{9051be2 token=Token{e661cad ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}}}
AppWindowToken{6e77b06 token=Token{f0fb1e1 ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}}}
AppWindowToken{e23349e token=Token{bd672d9 ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}}}


查看Activity#

adb shell dumpsys activity

主要关注

  • Running activities:该stack最近的Activity

    • TaskRecord:该stack最近的taskrecord

    • TaskId:#63 是com.shaunsheep.ams所在Task的TaskId

    • A:APP包名,com.shaunsheep.ams

    • StackId:Task所在的Stack栈

    • SZ:TaskRecord里面有几个Activity

      如Running activities有两个TaskRecod,#63有3个Activity,#62有2个Activity

      ActivityRecord的顺序从上往下看,MainActivity3、MainActivity2、MainActivity、HomeFirstSetWifiActivity、HomeUserProtocolActivity;

      TaskRecord的顺序从上往下看 #63 #62;

      Stack的存储顺序,就是从上往下看的ActivityRecord顺序,ActivityRecord中包含了TaskRecord信息,因此TaskRecord的展示是可以不连续的

      1
      2
      3
      4
      5
      6
      7
      8
      9
      Running activities (most recent first):
      TaskRecord{dbd02ff #63 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
      Run #4: ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}
      Run #3: ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}
      Run #2: ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}
      TaskRecord{9e28cc #62 A=com.unilife.fridge.haierbase.tft U=0 StackId=1 sz=2}
      Run #1: ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}
      Run #0: ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}

  • mResumedActivity:该stack栈顶的Activity

  • ResumedActivity:该stack栈顶的Activity

截取部分段落

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
Stack #1:
mFullscreen=true
isSleeping=false
mBounds=null
Task id #63
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
TaskRecord{dbd02ff #63 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.shaunsheep.ams/.MainActivity }
Hist #2: ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}
Intent { cmp=com.shaunsheep.ams/.MainActivity3 }
ProcessRecord{25d8a2a 9459:com.shaunsheep.ams/u0a57}
Hist #1: ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}
Intent { cmp=com.shaunsheep.ams/.MainActivity2 }
ProcessRecord{25d8a2a 9459:com.shaunsheep.ams/u0a57}
Hist #0: ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.shaunsheep.ams/.MainActivity }
ProcessRecord{25d8a2a 9459:com.shaunsheep.ams/u0a57}
Task id #62
mFullscreen=true
mBounds=null
mMinWidth=-1
mMinHeight=-1
mLastNonFullscreenBounds=null
TaskRecord{9e28cc #62 A=com.unilife.fridge.haierbase.tft U=0 StackId=1 sz=2}
Intent { act=com.unilife.fridge.HomeUserProtocolActivity flg=0x10000000 cmp=com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity }
Hist #1: ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}
Intent { act=com.unilife.fridge.HomeFirstSetWifiActivity flg=0x10000000 cmp=com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity }
ProcessRecord{60c9996 1341:com.unilife.fridge.haierbase.tft/u0a33}
Hist #0: ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}
Intent { act=com.unilife.fridge.HomeUserProtocolActivity flg=0x10000000 cmp=com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity }
ProcessRecord{60c9996 1341:com.unilife.fridge.haierbase.tft/u0a33}

Running activities (most recent first):
TaskRecord{dbd02ff #63 A=com.shaunsheep.ams U=0 StackId=1 sz=3}
Run #4: ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}
Run #3: ActivityRecord{618c5c4 u0 com.shaunsheep.ams/.MainActivity2 t63}
Run #2: ActivityRecord{40ee444 u0 com.shaunsheep.ams/.MainActivity t63}
TaskRecord{9e28cc #62 A=com.unilife.fridge.haierbase.tft U=0 StackId=1 sz=2}
Run #1: ActivityRecord{512920 u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeFirstSetWifiActivity t62}
Run #0: ActivityRecord{4b852ec u0 com.unilife.fridge.haierbase.tft/com.unilife.fridge.haiercommon.ui.activity.guide.HomeUserProtocolActivity t62}

mResumedActivity: ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}

Stack #0:
mFullscreen=true
isSleeping=false
mBounds=null

ResumedActivity: ActivityRecord{f8b5f48 u0 com.shaunsheep.ams/.MainActivity3 t63}
mFocusedStack=ActivityStack{868d01b stackId=1, 2 tasks} mLastFocusedStack=ActivityStack{868d01b stackId=1, 2 tasks}
mCurTaskIdForUser={0=63}
mUserStackInFront={}
mStacks={0=ActivityStack{ce525e2 stackId=0, 0 tasks}, 1=ActivityStack{868d01b stackId=1, 2 tasks}}
mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
0:[]
mLockTaskModeTasks[]
KeyguardController:
mKeyguardShowing=false
mKeyguardGoingAway=false
mOccluded=false
mDismissingKeyguardActivity=null
mDismissalRequested=false
mVisibilityTransactionDepth=0

Activity#

onBackPressed()
finish()
getTaskId 查看TaskId

UsageStatsManager#

Android获取栈顶程序
https://blog.csdn.net/ballonge/article/details/51085953
Android UsageStatsManager的简单使用
https://blog.csdn.net/shanfuming/article/details/58603450
http://blog.sina.com.cn/s/blog_7d95a2e70102vna4.html

task\stack#

task与stack有什么关系?

深入理解Android卷二 全文-第六章]深入理解ActivityManagerService_Innost的专栏-CSDN博客

Understand Android Activity’s launchMode: standard, singleTop, singleTask and singleInstance

tasks-and-back-stack

Application、Activity Stack 和 Task的区别

Android Stack与Task - 简书 (jianshu.com)

启动模式#

Activity启动模式singleTask的理解

Android启动模式之singleinstance的坑

好问题#

1.Stack、Task中,哪些因素影响Activity的展示顺序?

  • 启动模式
  • finsh、backPress
  • moveTaskToBack

2.SingleInstance使用越多越好吗?每个Activity都设置会怎么样?

点击查看
-------------------本文结束 感谢您的阅读-------------------