# 启动优化方法论
## 概述
应用启动速度直接影响用户体验,是性能优化的重要指标。本文档系统介绍Android应用启动优化的方法论、测量工具和优化策略。
## 启动类型
### 1. 冷启动(Cold Start)
**定义**: 应用进程不存在,系统需要创建新进程并初始化应用。
**特点**:
- 耗时最长
- 需要加载所有资源
- 创建Application和主Activity
**时间范围**: 通常2-5秒
### 2. 温启动(Warm Start)
**定义**: 应用进程存在但Activity被销毁,需要重新创建Activity。
**特点**:
- 进程已存在
- 只需创建Activity
- 比冷启动快
**时间范围**: 通常1-3秒
### 3. 热启动(Hot Start)
**定义**: 应用进程和Activity都存在,只需将Activity带到前台。
**特点**:
- 最快
- 只需恢复UI状态
- 几乎不需要初始化
**时间范围**: 通常< 500ms
## 启动时间测量
### 1. adb命令测量
```bash
# 测量启动时间
adb shell am start -W -n com.example.app/.MainActivity
# 输出示例:
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.app/.MainActivity }
# Status: ok
# Activity: com.example.app/.MainActivity
# ThisTime: 500
# TotalTime: 500
# WaitTime: 520
```
**指标说明**:
- **ThisTime**: 最后一个Activity启动耗时
- **TotalTime**: 所有Activity启动耗时
- **WaitTime**: AMS启动Activity总耗时
### 2. 代码埋点测量
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
long startTime = System.currentTimeMillis();
super.onCreate(savedInstanceState);
// 初始化工作
long endTime = System.currentTimeMillis();
Log.d("Startup", "onCreate耗时: " + (endTime - startTime) + "ms");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// 首帧渲染完成
long renderTime = System.currentTimeMillis() - getIntent().getLongExtra("start_time", 0);
Log.d("Startup", "首帧渲染耗时: " + renderTime + "ms");
}
}
}
```
### 3. Systrace/Perfetto分析
```bash
# 使用Systrace
python systrace.py -t 10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
# 使用Perfetto
# 通过Android Studio的Profiler录制
```
**关键指标**:
- **Application.onCreate**: Application初始化时间
- **Activity.onCreate**: Activity创建时间
- **inflate**: 布局解析时间
- **measure/layout/draw**: 视图测量、布局、绘制时间
### 4. 首屏渲染时间(TTI)
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 监听首屏渲染
View rootView = findViewById(android.R.id.content);
rootView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
rootView.getViewTreeObserver().removeOnPreDrawListener(this);
// 首屏已渲染
logTTI();
return true;
}
}
);
}
}
```
## 启动优化策略
### 1. Application优化
#### 延迟初始化
```java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 立即初始化:必须的、轻量的
initCrashHandler();
// 延迟初始化:非关键的、耗时的
initInBackground();
}
private void initInBackground() {
new Thread(() -> {
// 在后台线程初始化
initHeavyLibrary();
initThirdPartySDK();
}).start();
}
}
```
#### 使用启动器框架
```java
// 使用Startup库管理初始化任务
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
AppStartup.initializeComponent(this, MyStartupInitializer.class);
}
}
```
### 2. 主线程优化
#### 减少主线程工作
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 避免在主线程做耗时操作
// ❌ 错误:同步网络请求
// String data = networkRequest();
// ✅ 正确:异步加载
loadDataAsync();
setContentView(R.layout.activity_main);
}
private void loadDataAsync() {
new Thread(() -> {
String data = networkRequest();
runOnUiThread(() -> {
updateUI(data);
});
}).start();
}
}
```
#### 使用IdleHandler延迟非关键任务
```java
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// 主线程空闲时执行
initNonCriticalComponents();
return false; // false表示只执行一次
}
});
```
### 3. 布局优化
#### 减少布局层级
```xml
```
#### 使用ViewStub延迟加载
```xml
```
```java
// 需要时再加载
ViewStub viewStub = findViewById(R.id.view_stub);
viewStub.inflate();
```
#### 优化布局inflate
```java
// 使用AsyncLayoutInflater异步加载布局
new AsyncLayoutInflater(this).inflate(
R.layout.activity_main,
null,
(view, resid, parent) -> {
setContentView(view);
// 布局已加载完成
}
);
```
### 4. 资源优化
#### 减少启动时加载的资源
```java
// 延迟加载大图片
// 使用占位图
ImageView imageView = findViewById(R.id.image);
imageView.setImageResource(R.drawable.placeholder);
// 异步加载
Glide.with(this)
.load(imageUrl)
.into(imageView);
```
#### 使用资源预加载
```java
// 在Application中预加载常用资源
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 预加载资源到内存
preloadResources();
}
private void preloadResources() {
new Thread(() -> {
// 预加载常用drawable
Resources res = getResources();
res.getDrawable(R.drawable.common_icon);
}).start();
}
}
```
### 5. 多进程优化
```xml
```
**优点**:
- 主进程启动更快
- 避免主进程OOM
- 隔离崩溃影响
**缺点**:
- 进程间通信开销
- 内存占用增加
### 6. 类加载优化
#### 减少类数量
```java
// 使用ProGuard/R8混淆和优化
// build.gradle
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
```
#### 使用MultiDex优化
```java
// 对于方法数超过65535的应用
android {
defaultConfig {
multiDexEnabled true
}
}
dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
}
```
### 7. 启动画面优化
#### 使用Splash Screen API(Android 12+)
```java
// 使用新的Splash Screen API
// 提供更好的启动体验
```
#### 传统启动画面
```java
// 快速显示启动画面
// 避免白屏/黑屏
```
## 启动优化检查清单
### Application层
- [ ] 延迟非关键初始化
- [ ] 使用后台线程初始化耗时任务
- [ ] 避免在Application中做网络请求
- [ ] 使用启动器框架管理初始化顺序
### Activity层
- [ ] 减少onCreate中的工作
- [ ] 异步加载数据
- [ ] 使用ViewStub延迟加载
- [ ] 优化布局层级
### 资源层
- [ ] 减少启动时加载的资源
- [ ] 使用占位图
- [ ] 延迟加载大图片
- [ ] 优化资源大小
### 代码层
- [ ] 减少类数量(使用ProGuard)
- [ ] 避免静态初始化块中的耗时操作
- [ ] 优化依赖库加载
## 性能指标
### 目标值
- **冷启动**: < 2秒
- **温启动**: < 1秒
- **热启动**: < 500ms
- **首屏渲染**: < 1秒
### 测量方法
1. 使用adb命令测量
2. 代码埋点测量
3. Systrace/Perfetto分析
4. 用户感知时间测量
## 相关链接
- [[README]]
- [[流畅度(Choreographer+VSYNC)]]
- [[09-调试与工具链/Systrace_Perfetto全解读]]