1. 启动 App 的流程
大致分为两类:冷启动和热启动。
冷启动:App 生命周期已结束,被重新拉起。
热启动:App 生命周期存活,可能处于后台,被重新拉起到前台。
示例:以从 Launcher 应用池点开一个 App 为例,经历几个节点:
- Launcher 进程发出建立 App 的请求。
- System_server 中的 ActivityService 处理传进来的创建 App 的请求,在这里有个判断逻辑,判断此 App 是热启动还是冷启动。
- 如果是冷启动,先走 zygote 创建 App 进程;如果是热启动,直接进入第 4 步。
- 进入到 App 进程。
这里可以参考链接:Android应用启动流程一次看透_android startinstrumentation-CSDN博客
2. Android 的窗口构成
已知大概组成结构如下,连接设备后执行 dumpsys activity 取一段日志如下:
3. 举例一个场景
我创建了几个 Activity:MainActivity(standard)、HomeActivity(singleTask)、CarDetectActivity(standard)。其中mainactivity有个业务流程,在create的时候会自动拉起homeactivity。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".CarDetectActivity"
android:exported="false"
android:theme="@style/Theme.MyApplication" />
<activity
android:name=".HomeActivity"
android:exported="false"
android:launchMode="singleTask"
android:theme="@style/Theme.MyApplication" />
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.MyApplication">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
首先我通过依次打开 MainActivity → HomeActivity → CarDetectActivity。
Task 中的 ActivityRecord 记录如下:

3.1 通过命令行:重新启动 MainActivity,这个 flag 是将 Task 中已有的 Activity 复用到栈顶
am start -n com.example.myapplication/.MainActivity -f 0x00020000
。
此时再执行 dumpsys activity 信息如下:可以看到 MainActivity 被移动到了栈顶,且里面的记录号没变。

3.2 通过命令行启动页面,不带flag的方式
am start -n com.example.myapplication/.MainActivity
通过命令行 dumpsys activity | grep -A 20 "Task display areas" 查看,此时是没有复用的。
栈内信息从:

变成了:

这是由于在该task中新建了 MainActivity,而 MainActivity 是重新 create 的。create 中有 HomeActivity 的流程,这里 resume 原来的 HomeActivity。而 HomeActivity 的 launchMode 是 singleTask,然后 HomeActivity 需要把它上面的 Activity 都清理掉,也就是把新建的 MainActivity 和上面的 CarDetectActivity 都销毁掉。
可以看见下面的日志是符合逻辑的:首先创建一个 MainActivity,然后 HomeActivity 被 restart 复用。它上面的 CarDetectActivity 被 destroy,刚才新建的 MainActivity 生命周期也 destroy。
日志如下:

结论:
- Activity启动不是创建Activity,而是一次Task/Activity匹配过程
- ActivityRecord是否复用由flag和launchMode共同决定
- singleTask最大的影响不是复用,而是清理栈
- Task的baseIntent决定Task身份,会影响后续启动匹配
- 看到Activity生命周期异常,要先分析Task栈变化,而不是只看Activity代码