13 KiB
13 KiB
启动优化
目录
启动流程分析
应用启动类型
1. 冷启动(Cold Start)
- 定义:系统进程中没有该应用的任何进程信息,需要创建新进程
- 特点:启动时间最长,需要加载所有资源
- 流程:
- 启动进程
- 创建Application对象
- 启动主线程
- 创建主Activity
- 加载布局
- 执行onCreate
- 测量、布局、绘制
- 显示到屏幕
2. 热启动(Hot Start)
- 定义:应用进程还在,只是Activity被销毁
- 特点:启动时间短,只需恢复Activity
- 流程:
- 恢复Activity
- 调用onCreate、onStart、onResume
- 显示到屏幕
3. 温启动(Warm Start)
- 定义:应用进程存在,但Activity需要重建
- 特点:介于冷启动和热启动之间
启动时间线
进程创建 → Application创建 → Activity创建 → 布局加载 → 首帧绘制
启动时间测量
1. 使用 adb 命令测量
# 测量冷启动时间
adb shell am start -W -n com.example.app/.MainActivity
# 输出示例:
# ThisTime: 500ms # 最后一个Activity启动耗时
# TotalTime: 800ms # 所有Activity启动耗时
# WaitTime: 1000ms # 系统启动应用耗时
2. 代码中测量
// Application onCreate
@Override
public void onCreate() {
super.onCreate();
long startTime = System.currentTimeMillis();
// 初始化代码
long endTime = System.currentTimeMillis();
Log.d("Startup", "Application onCreate: " + (endTime - startTime) + "ms");
}
// Activity onCreate
@Override
protected void onCreate(Bundle savedInstanceState) {
long startTime = System.currentTimeMillis();
super.onCreate(savedInstanceState);
// 初始化代码
long endTime = System.currentTimeMillis();
Log.d("Startup", "Activity onCreate: " + (endTime - startTime) + "ms");
}
3. 使用 TraceView
// 开始追踪
Debug.startMethodTracing("startup");
// 结束追踪
Debug.stopMethodTracing();
4. 使用 Systrace/Perfetto
# 使用 Systrace
python systrace.py -t 10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res
# 使用 Perfetto
# 在开发者选项中启用系统追踪
冷启动优化
1. Application 优化
延迟初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 必要初始化(立即执行)
initCrashHandler();
// 非必要初始化(延迟执行)
new Handler(Looper.getMainLooper()).postDelayed(() -> {
initThirdPartySDK();
}, 100);
}
}
异步初始化
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 使用线程池异步初始化
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(() -> {
initHeavySDK();
});
}
}
使用 ContentProvider 初始化(不推荐)
// 不推荐:ContentProvider 的 onCreate 在 Application onCreate 之前执行
// 会阻塞主线程
public class InitProvider extends ContentProvider {
@Override
public boolean onCreate() {
// 初始化代码
return true;
}
}
2. Activity 优化
减少 onCreate 耗时
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1. 延迟非关键初始化
new Handler().post(() -> {
initNonCriticalComponents();
});
// 2. 使用 ViewStub 延迟加载
ViewStub viewStub = findViewById(R.id.view_stub);
viewStub.inflate(); // 需要时才加载
// 3. 异步加载数据
loadDataAsync();
}
使用启动窗口
<!-- styles.xml -->
<style name="LaunchTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/launch_screen</item>
<item name="android:windowFullscreen">true</item>
</style>
<!-- AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:theme="@style/LaunchTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
// MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme); // 恢复正常主题
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
3. 布局优化
减少布局层级
<!-- 优化前:嵌套过多 -->
<LinearLayout>
<LinearLayout>
<LinearLayout>
<TextView />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 优化后:使用 ConstraintLayout -->
<androidx.constraintlayout.widget.ConstraintLayout>
<TextView />
</androidx.constraintlayout.widget.ConstraintLayout>
使用 ViewStub
<ViewStub
android:id="@+id/view_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/heavy_layout" />
// 需要时才加载
ViewStub viewStub = findViewById(R.id.view_stub);
viewStub.inflate();
使用 Merge 标签
<!-- include_layout.xml -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_width="wrap_content" />
<Button android:layout_width="wrap_content" />
</merge>
4. 资源优化
减少资源大小
- 使用 WebP 格式图片
- 压缩图片资源
- 移除未使用的资源
- 使用矢量图(SVG)
延迟加载资源
// 使用 Glide 等图片加载库延迟加载
Glide.with(this)
.load(url)
.into(imageView);
5. 多进程优化
<!-- AndroidManifest.xml -->
<application>
<!-- 主进程:只保留必要的组件 -->
<activity android:name=".MainActivity" />
<!-- 后台进程:处理耗时操作 -->
<service
android:name=".BackgroundService"
android:process=":background" />
</application>
热启动优化
1. 避免重建 Activity
// 在 onSaveInstanceState 中保存状态
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("key", value);
}
// 在 onCreate 中恢复状态
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String value = savedInstanceState.getString("key");
}
}
2. 使用 ViewModel
public class MainViewModel extends ViewModel {
private MutableLiveData<String> data = new MutableLiveData<>();
public LiveData<String> getData() {
return data;
}
}
// Activity 中使用
public class MainActivity extends AppCompatActivity {
private MainViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MainViewModel.class);
// ViewModel 在配置变更时不会重建
}
}
3. 配置变更处理
<!-- AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden" />
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// 手动处理配置变更,避免重建 Activity
}
启动优化方案
1. 启动任务管理
public class StartupTaskManager {
private static final List<StartupTask> tasks = new ArrayList<>();
public static void addTask(StartupTask task) {
tasks.add(task);
}
public static void executeTasks() {
ExecutorService executor = Executors.newCachedThreadPool();
for (StartupTask task : tasks) {
if (task.runOnMainThread()) {
task.run();
} else {
executor.execute(task::run);
}
}
}
}
interface StartupTask {
void run();
boolean runOnMainThread();
int priority(); // 优先级
}
2. 启动白屏优化
// 使用启动窗口主题
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/splash_background</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
</style>
3. 预加载优化
// 在 Application 中预加载
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 预加载常用数据
preloadData();
// 预初始化 View
preloadViews();
}
private void preloadData() {
// 预加载数据到内存
}
private void preloadViews() {
// 预创建 View 对象
}
}
启动优化工具
1. Android Studio Profiler
- CPU Profiler:分析启动时的 CPU 使用
- Memory Profiler:分析内存分配
- Network Profiler:分析网络请求
2. Systrace/Perfetto
- 系统级性能分析
- 查看启动时间线
- 分析各组件耗时
3. TraceView
- 方法级性能分析
- 查看方法调用栈
- 分析耗时方法
4. 自定义工具
public class StartupTracker {
private static final Map<String, Long> timings = new HashMap<>();
public static void start(String tag) {
timings.put(tag, System.currentTimeMillis());
}
public static void end(String tag) {
Long startTime = timings.get(tag);
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
Log.d("Startup", tag + ": " + duration + "ms");
}
}
}
// 使用
StartupTracker.start("Application.onCreate");
// ... 代码 ...
StartupTracker.end("Application.onCreate");
面试常见问题
Q1: 如何测量应用的启动时间?
答案:
- 使用
adb shell am start -W命令 - 在代码中使用
System.currentTimeMillis()记录时间点 - 使用 TraceView 或 Systrace 工具
- 使用 Android Studio Profiler
Q2: 冷启动和热启动的区别?
答案:
- 冷启动:系统进程中没有应用进程,需要创建新进程,耗时最长
- 热启动:应用进程还在,只需恢复 Activity,耗时最短
- 温启动:应用进程存在,但 Activity 需要重建,耗时介于两者之间
Q3: Application onCreate 中应该做什么?
答案:
- 只做必要的初始化
- 非必要的初始化应该延迟或异步执行
- 避免在主线程执行耗时操作
- 避免初始化过多第三方 SDK
Q4: 如何优化启动速度?
答案:
- Application 优化:延迟初始化、异步初始化
- Activity 优化:减少 onCreate 耗时、使用启动窗口
- 布局优化:减少层级、使用 ViewStub、Merge 标签
- 资源优化:压缩资源、使用 WebP、移除未使用资源
- 多进程优化:将耗时操作放到后台进程
Q5: 启动白屏问题如何解决?
答案:
- 使用启动窗口主题(Splash Theme)
- 设置合适的 windowBackground
- 使用启动画面(Splash Screen)
- 尽快显示首帧内容
Q6: ViewStub 的作用是什么?
答案:
- ViewStub 是一个轻量级的 View,用于延迟加载布局
- 只有在调用
inflate()时才会加载实际布局 - 可以减少初始布局的复杂度,提升启动速度
Q7: 如何避免 Activity 重建?
答案:
- 使用 ViewModel 保存数据
- 在 onSaveInstanceState 中保存状态
- 处理配置变更(configChanges)
- 使用 Fragment 保存状态
Q8: 启动优化的最佳实践?
答案:
- 测量启动时间,找出瓶颈
- 延迟非关键初始化
- 异步执行耗时操作
- 优化布局层级
- 使用启动窗口
- 减少资源大小
- 使用多进程分离耗时操作
总结
启动优化是 Android 性能优化的重要部分,主要从以下几个方面入手:
- Application 优化:延迟初始化、异步初始化
- Activity 优化:减少 onCreate 耗时、使用启动窗口
- 布局优化:减少层级、使用 ViewStub
- 资源优化:压缩资源、延迟加载
- 架构优化:使用多进程、任务管理
通过合理的优化,可以将冷启动时间从 2-3 秒降低到 1 秒以内。
最后更新:2024年