singleTask 清栈过程中 Activity 销毁与目标 Activity 恢复的时序分析

1. 启动 App 的流程

大致分为两类:冷启动和热启动。

冷启动:App 生命周期已结束,被重新拉起。

热启动:App 生命周期存活,可能处于后台,被重新拉起到前台。

示例:以从 Launcher 应用池点开一个 App 为例,经历几个节点:

  1. Launcher 进程发出建立 App 的请求。
  2. System_server 中的 ActivityService 处理传进来的创建 App 的请求,在这里有个判断逻辑,判断此 App 是热启动还是冷启动。
  3. 如果是冷启动,先走 zygote 创建 App 进程;如果是热启动,直接进入第 4 步。
  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代码
相关推荐
心平气和量大福大10 分钟前
android-控件-单选框RadioButton
android
Meteors.17 分钟前
Android 性能优化:08.耗电优化
android·性能优化
Kapaseker44 分钟前
Compose SelectionState API — 主动控制文本选择
android·kotlin
拾光Ծ2 小时前
【MySQL】对表数据的操作:增删查改(CRUD)
android·数据库·sql·mysql
一笑的小酒馆12 小时前
Android中的tcp通信
android
默阳123415 小时前
2026年Android中高级面试题专栏(Android进阶篇)
android
古法安卓16 小时前
Android-日志系统源码解析
android·java·android studio
恋猫de小郭17 小时前
Android 17 + OkHttp 5.5.0 ,全新 ECH 下你的 HTTPS 域名可以请求时被安全隐藏
android·前端·flutter
小强闯江湖17 小时前
不只是让 AI 写代码:ViewCompose 把 Android UI 做成了可编译、可渲染的闭环
android·人工智能·kotlin