# 启动优化方法论 ## 概述 应用启动速度直接影响用户体验,是性能优化的重要指标。本文档系统介绍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全解读]]