一、用户点击图标:触发启动
比喻:就像你下单外卖,触发餐厅接单流程。
- Launcher(桌面)收到点击事件
- 桌面本质也是一个App,它通过
PackageManager
找到你点击的App信息(如包名、入口Activity)。
- 桌面本质也是一个App,它通过
- 向系统发起启动请求
- 通过
Binder
跨进程通信,告诉ActivityManagerService
(AMS):"用户要启动XX App!"
- 通过
二、系统调度:AMS分配任务
比喻:AMS像餐厅的"调度中心",决定订单分配给哪个厨师。
- AMS检查权限和条件
- 是否有权限启动?
- App是否已安装?
- 是否需要新建进程(首次启动)?
- 分配进程
- 如果App未运行,AMS通过
Zygote
fork一个新进程(克隆一个预加载好的模板进程)。 - 优化点 :Android 8.0后引入
Zygote预加载类
,加速启动。
- 如果App未运行,AMS通过
三、App进程初始化:从空白到就绪
比喻:新厨师到岗,准备工具和食材。
- 进程创建后,执行入口方法
ActivityThread.main()
是App进程的入口(相当于厨师报到)。
- 绑定到AMS
- 通过
ApplicationThread
(Binder代理)和AMS通信,告诉AMS:"我准备好了!"
- 通过
- 创建Application对象
- 系统回调
Application.onCreate()
,这里是全局初始化代码的位置(比如初始化SDK)。
- 系统回调
四、Activity启动:界面构建
比喻:厨师开始做菜,最终上桌。
-
AMS通知App创建Activity
- 通过Binder调用
ActivityThread.Handler
,发送LAUNCH_ACTIVITY
消息。
- 通过Binder调用
-
Activity生命周期回调
javaonCreate() → onStart() → onResume()
onCreate()
:加载布局(setContentView
)、初始化数据。onResume()
:界面可见,可交互(相当于菜品上桌)。
-
UI渲染完成
- 经过
ViewRootImpl
触发measure/layout/draw
流程,最终界面显示。
- 经过
五、冷启动 vs 热启动
类型 | 触发条件 | 耗时原因 | 优化手段 |
---|---|---|---|
冷启动 | App进程不存在 | 需创建进程+加载类+初始化 | 减少Application 初始化逻辑 |
热启动 | App进程在后台 | 只需恢复Activity | 避免onCreate 重复加载数据 |
六、核心流程图
plaintext
[点击图标] → Launcher → AMS → Zygote fork进程
↓ ↓
(权限检查) → ActivityThread.main()
↓
Application.onCreate()
↓
Activity生命周期(onCreate→onResume)
↓
UI渲染 → 界面显示
七、常见面试题速答
❓ Q1:App启动慢的可能原因?
- 冷启动:
Application
初始化代码太多(如第三方SDK初始化)。 - UI线程阻塞:
onCreate
中执行耗时操作(如数据库查询)。
❓ Q2:如何优化启动速度?
- 代码层面 :
- 懒加载非必要SDK(按需初始化)。
- 使用
SplashScreen
API(Android 12+)。
- 工具层面 :
- 用
adb shell am start -W
测量启动时间。 - 通过
Systrace
分析阻塞点。
- 用
❓ Q3:启动阶段为什么不能ANR?
- ANR触发条件是主线程阻塞5秒以上,但启动阶段系统不会检测ANR(只有用户交互后才会触发)。
八、总结
安卓App启动的本质:
进程创建 → 组件初始化 → UI渲染
理解这个流程后,无论是优化性能还是解决启动问题,都能直击要害!