Android 启动模式

相关的概念

关系图

  1. ActivityStack

    应用程序在一个单例的 ActivityStack 中,一个 ActivityStack 可能包含了多个 task

  2. TaskRecord

    1. 一个进程(程序)有一个默认的task affinity,默认为包名
    2. Activity 会进入启动它的 Activity 所在的 Task 栈中
    3. app 的切换实质上就是 task 栈的切换
  3. ActivityRecord

    包含了一个Activity的所有信息,例如所在 task、所在进程的信息 ProcessRecord 等

  4. ProcessRecord

    当前运行的进程信息

四种启动模式

  1. standard

    1. Activity 会重新创建一个新的实例,不论原有实例是否存在。
  2. singleTop

    栈顶复用,要创建的 Activity 已经处于栈顶时,此时会直接复用栈顶的 Activity,不调用 onCreate、onStart,回调 onNewIntent

    与使用 Intent.FLAG_ACTIVITY_SINGLE_TOP 等价

    场景:消息推送界面。防止重复推送,多次打开某个页面

  3. singleTask

    要创建的 Activity 已经处于栈中时,此时不会创建新的 Activity,而是将存在栈中的 Activity 上面的其他 Activity 所有销毁,使它成为栈顶

    与使用 Intent.FLAG_ACTIVITY_CLEAR_TOP 等价

    场景:主页

  4. singleInstance

    会复用已有的 activity,且栈中只有一个 activity

    场景:呼叫来电界面

FLAG

FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_NEW_TASK 会先判断 activity 的 taskAffinity 指定的 task 是否已存在,如果已存在则不会新建 task,不存在则新建 task。如果配合 FLAG_ACTIVITY_MULTIPLE_TASK 一起使用,则不搜索是否已有 task,都会新建新的 task。

在 Service 中或使用 applicationContext 启动 Activity 必须要有该 flag。

FLAG_ACTIVITY_MULTIPLE_TASK

(FLAG_ACTIVITY_MULTIPLE_TASK)[https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_MULTIPLE_TASK]

This flag is used to create a new task and launch an activity into it. This flag is always paired with either FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK. In both cases these flags alone would search through existing tasks for ones matching this Intent. Only if no such task is found would a new task be created. When paired with FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors are modified to skip the search for a matching task and unconditionally start a new task.

举个栗子:

KotlinActivity 中只是用 FLAG_ACTIVITY_NEW_TASK 启动 activity,两个 activity 会在同一个 task 中。如果使用 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK 启动 Main2Activity。两个 activity 会在不同的 task 中,但是 taskAffinity 是一样的,没指定默认是包名。

在 Service 中启动结果是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
newTask+mutable 后,task 是什么样

Task id #771
TaskRecord{750276f #771 A=com.andy.demo U=0 sz=1}
Intent { flg=0x18000000 cmp=com.andy.demo/.Main2Activity }
Hist #0: ActivityRecord{c6870ec u0 com.andy.demo/.Main2Activity t771}
Intent { flg=0x18000000 cmp=com.andy.demo/.Main2Activity }
ProcessRecord{c9f9567 32573:com.andy.demo/u0a251}

Task id #770
TaskRecord{4222f14 #770 A=com.andy.demo U=0 sz=1}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.andy.demo/.KotlinActivity }
Hist #0: ActivityRecord{447e0c4 u0 com.andy.demo/.KotlinActivity t770}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.andy.demo/.KotlinActivity }
ProcessRecord{c9f9567 32573:com.andy.demo/u0a251}

附 adb 命令

adb shell dumpsys activity activities 获取运行的 activity