一、引言:为什么必须搞懂 Activity 启动流程?
很多 Android 开发者在日常开发中都会写:
startActivity(Intent(this, DetailActivity::class.java))
看起来简单,但你有没有遇到过这些问题:
- 为什么 冷启动慢?
- 为什么有时候会 白屏/黑屏?
onCreate()到底什么时候被调用?- 多进程/多任务栈下,为什么行为“奇怪”?
- 启动优化该从哪下手?
👉 本质上,这些问题都指向同一个核心:Activity 启动流程。
如果你不了解这条链路,就只能“猜”;
但一旦理解了,就能做到:
- 精准定位启动性能瓶颈
- 正确设计页面跳转结构
- 避免生命周期误用
- 做出真正有效的优化
二、背景知识:你需要知道的几个关键角色
在深入之前,我们先建立一个“地图”:
1. 进程划分(非常关键)
-
App 进程
- 执行你的代码
- 包含 Activity、View、业务逻辑
-
System Server 进程
- 系统核心服务
- 包含 AMS(ActivityManagerService)
👉 一句话总结:
Activity 启动 = App 进程请求 → System Server 决策 → 再回调 App
2. 核心组件
| 组件 | 作用 |
|---|---|
| Activity | 页面 |
| AMS | 调度 Activity |
| ATMS | 专门管理 Activity(Android 10+) |
| Instrumentation | 启动 Activity 的“执行器” |
| ActivityThread | App 主线程的入口 |
3. 启动方式
- 显式启动
- 隐式启动
- 冷启动 / 热启动 / 温启动
👉 后面我们重点讲 冷启动路径(最复杂)
三、核心原理解析:一张图看懂启动流程
我们先用一句话总结:
Activity 启动 = 一次跨进程调用 + 一次进程创建 + 一次生命周期分发
拆开来看是这样:
App.startActivity()
↓
AMS(系统进程)
↓
(如果进程不存在)Zygote fork 新进程
↓
ActivityThread(主线程)
↓
Instrumentation 创建 Activity
↓
onCreate → onStart → onResume
四、源码级流程分析(重点)
我们从一行代码开始:
startActivity(Intent(this, DetailActivity::class.java))
Step 1:Activity.startActivity()
public void startActivity(Intent intent) {
Instrumentation.execStartActivity(...)
}
👉 关键点:
- Activity 自己并不启动 Activity
- 它把任务交给了 Instrumentation
Step 2:Instrumentation.execStartActivity()
ActivityTaskManager.getService().startActivity(...)
👉 这里发生了什么?
- 通过 Binder 调用系统服务
- 跨进程进入 System Server
Step 3:进入 AMS / ATMS(系统进程)
核心逻辑:
ActivityStarter.execute()
它会做几件关键事情:
① 解析 Intent
- 找到目标 Activity
- 检查权限
② 处理任务栈(Task)
- 是否复用已有 Activity?
- 是否创建新 Task?
③ 判断进程是否存在
👉 关键分支:
| 情况 | 行为 |
|---|---|
| 进程已存在 | 直接调度 |
| 进程不存在 | 创建新进程 |
Step 4:如果进程不存在 → 创建进程(冷启动关键)
ZygoteProcess.start(...)
👉 本质:
通过 Zygote fork 一个新进程
新进程启动后会执行:
ActivityThread.main()
Step 5:ActivityThread 处理启动
系统会通过 Binder 回调:
scheduleLaunchActivity()
然后在主线程执行:
handleLaunchActivity()
Step 6:创建 Activity 实例
val activity = mInstrumentation.newActivity(...)
👉 本质:
反射创建 Activity 对象
Step 7:生命周期回调
activity.performCreate()
activity.performStart()
activity.performResume()
最终调用:
onCreate()
onStart()
onResume()
⭐ 到这里,页面才真正显示出来
五、实战示例:模拟 Activity 启动过程
我们写一个简单 Demo 来观察流程:
示例代码
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
log("onCreate")
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.btn).setOnClickListener {
startActivity(Intent(this, DetailActivity::class.java))
}
}
override fun onStart() {
super.onStart()
log("onStart")
}
override fun onResume() {
super.onResume()
log("onResume")
}
private fun log(msg: String) {
Log.d("MainActivity", msg)
}
}
观察点
点击按钮后,你会看到:
MainActivity onPause
DetailActivity onCreate
DetailActivity onStart
DetailActivity onResume
MainActivity onStop
👉 这说明:
新 Activity Resume 后,旧 Activity 才 Stop
六、常见误区 / 踩坑总结
❌ 误区 1:startActivity 就是直接 new Activity
👉 错!
真实过程是:
跨进程 + 系统调度 + 生命周期驱动
❌ 误区 2:onCreate 一定很快执行
👉 不一定!
如果是冷启动:
- 进程创建(几十 ms)
- Application 初始化
- View inflate
👉 可能 几百毫秒甚至更慢
❌ 误区 3:页面卡顿一定是 Activity 问题
👉 实际可能是:
- Application 太重
- ContentProvider 初始化
- 主线程 IO
❌ 误区 4:任务栈行为可预测
👉 如果你不理解:
- launchMode
- taskAffinity
👉 行为会“非常玄学”
七、性能优化 & 最佳实践(重点加分)
1. 冷启动优化核心路径
冷启动时间 =
进程创建 + Application + Activity
优化建议:
✅ 减少 Application 初始化
// ❌ 不要在 Application 做重操作
override fun onCreate() {
initSDK() // 耗时
}
👉 改为延迟初始化:
Handler(Looper.getMainLooper()).post {
initSDK()
}
2. 减少首屏布局复杂度
<!-- ❌ 深层嵌套 -->
LinearLayout
LinearLayout
RelativeLayout
👉 使用:
- ConstraintLayout
- ViewStub
3. 使用启动占位(避免白屏)
<style name="AppTheme" parent="Theme.MaterialComponents">
<item name="android:windowBackground">@drawable/launch_bg</item>
</style>
4. 避免主线程阻塞
// ❌
val data = loadFromDisk()
// ✅
lifecycleScope.launch {
val data = withContext(Dispatchers.IO) {
loadFromDisk()
}
}
5. Activity 启动链路优化
👉 常见问题:
- 多层跳转(Splash → Login → Home)
👉 优化:
合并跳转,减少中间 Activity
八、总结:你真正需要记住的 5 件事
1️⃣ Activity 启动不是函数调用,而是系统调度
2️⃣ 核心链路:
App → AMS → Zygote → ActivityThread → 生命周期
3️⃣ 冷启动慢,本质是“进程创建 + 初始化”
4️⃣ 生命周期不是“回调”,而是“系统驱动”
5️⃣ 优化启动 = 优化主线程 + 减少初始化 + 控制布局复杂度
最后一句
你写的是 startActivity,但系统做的是一整套进程调度系统。
理解这件事,是从“会用 Android”走向“掌控 Android”的分水岭。