Files
mkdocs/docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md
renjianbo 8a4717277d 测试
2026-01-12 17:14:58 +08:00

9.4 KiB
Raw Blame History

启动优化方法论

概述

应用启动速度直接影响用户体验是性能优化的重要指标。本文档系统介绍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命令测量

# 测量启动时间
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. 代码埋点测量

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分析

# 使用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

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优化

延迟初始化

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        
        // 立即初始化:必须的、轻量的
        initCrashHandler();
        
        // 延迟初始化:非关键的、耗时的
        initInBackground();
    }
    
    private void initInBackground() {
        new Thread(() -> {
            // 在后台线程初始化
            initHeavyLibrary();
            initThirdPartySDK();
        }).start();
    }
}

使用启动器框架

// 使用Startup库管理初始化任务
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        AppStartup.initializeComponent(this, MyStartupInitializer.class);
    }
}

2. 主线程优化

减少主线程工作

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延迟非关键任务

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
    @Override
    public boolean queueIdle() {
        // 主线程空闲时执行
        initNonCriticalComponents();
        return false; // false表示只执行一次
    }
});

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="@layout/heavy_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
// 需要时再加载
ViewStub viewStub = findViewById(R.id.view_stub);
viewStub.inflate();

优化布局inflate

// 使用AsyncLayoutInflater异步加载布局
new AsyncLayoutInflater(this).inflate(
    R.layout.activity_main,
    null,
    (view, resid, parent) -> {
        setContentView(view);
        // 布局已加载完成
    }
);

4. 资源优化

减少启动时加载的资源

// 延迟加载大图片
// 使用占位图
ImageView imageView = findViewById(R.id.image);
imageView.setImageResource(R.drawable.placeholder);

// 异步加载
Glide.with(this)
    .load(imageUrl)
    .into(imageView);

使用资源预加载

// 在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. 多进程优化

<!-- AndroidManifest.xml -->
<activity
    android:name=".MainActivity"
    android:process=":main" />
    
<service
    android:name=".HeavyService"
    android:process=":heavy" />

优点:

  • 主进程启动更快
  • 避免主进程OOM
  • 隔离崩溃影响

缺点:

  • 进程间通信开销
  • 内存占用增加

6. 类加载优化

减少类数量

// 使用ProGuard/R8混淆和优化
// build.gradle
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                    'proguard-rules.pro'
        }
    }
}

使用MultiDex优化

// 对于方法数超过65535的应用
android {
    defaultConfig {
        multiDexEnabled true
    }
}

dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
}

7. 启动画面优化

使用Splash Screen APIAndroid 12+

// 使用新的Splash Screen API
// 提供更好的启动体验

传统启动画面

// 快速显示启动画面
// 避免白屏/黑屏
<style name="LaunchTheme" parent="Theme.AppCompat.Light">
    <item name="android:windowBackground">@drawable/splash_background</item>
    <item name="android:windowFullscreen">true</item>
</style>

启动优化检查清单

Application层

  • 延迟非关键初始化
  • 使用后台线程初始化耗时任务
  • 避免在Application中做网络请求
  • 使用启动器框架管理初始化顺序

Activity层

  • 减少onCreate中的工作
  • 异步加载数据
  • 使用ViewStub延迟加载
  • 优化布局层级

资源层

  • 减少启动时加载的资源
  • 使用占位图
  • 延迟加载大图片
  • 优化资源大小

代码层

  • 减少类数量使用ProGuard
  • 避免静态初始化块中的耗时操作
  • 优化依赖库加载

性能指标

目标值

  • 冷启动: < 2秒
  • 温启动: < 1秒
  • 热启动: < 500ms
  • 首屏渲染: < 1秒

测量方法

  1. 使用adb命令测量
  2. 代码埋点测量
  3. Systrace/Perfetto分析
  4. 用户感知时间测量

相关链接