安卓性能调优之-检测应用启动速度

先来了解一下几种应用启动的概念:

冷启动(Cold Start):应用完全未启动,模拟全新启动过程。

暖启动(Warm Start) :进程仍然存活,但 Activity可能需要重新创建。

热启动(Hot Start) :进程存活,Activity只是从 onStop 恢复到 onResume

adb命令检测

shell 复制代码
adb shell am start -W com.example.quickdev/com.example.quickdev.ui.activity.SplashActivity

或者使用:

shell 复制代码
adb shell am start -S -W com.example.quickdev/.ui.activity.SplashActivity

-S 参数会强制停止目标 Activity -W:等待启动完成并打印耗时(关键参数)

  • 执行结果-冷启动
shell 复制代码
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.quickdev/.ui.activity.SplashActivity }
Status: ok
LaunchState: COLD
Activity: com.example.quickdev/.ui.activity.SplashActivity
TotalTime: 1573
WaitTime: 1575
Complete
  • 执行结果-热启动
shell 复制代码
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.quickdev/.ui.activity.SplashActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
LaunchState: HOT
Activity: com.example.quickdev/.ui.activity.HomeActivity
TotalTime: 136
WaitTime: 138
Complete
  • 执行结果-暖启动
shell 复制代码
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.quickdev/.ui.activity.SplashActivity }
Status: ok
LaunchState: WARM
Activity: com.example.quickdev/.ui.activity.SplashActivity
TotalTime: 259
WaitTime: 262
Complete
字段 含义 单位 备注
Status 启动状态 - ok 表示成功,error 表示失败
LaunchState 启动类型 - COLD(冷启动)/WARM(温启动)/HOT(热启动)
Activity 实际启动的 Activity - 可能被 Intent Filter 重定向
TotalTime Activity 自身启动耗时 毫秒(ms) 从创建到首帧完成
WaitTime 系统总等待时间 毫秒(ms) 包括系统资源准备时间
Complete 完成标记 - 仅表示命令执行完毕

启动类型(LaunchState)

  • COLD:完全冷启动(进程不存在)
  • WARM:温启动(进程存在但Activity被销毁)
  • HOT:热启动(Activity仍在栈中)

时间统计原理

  • TotalTime:通过 ActivityRecord 的 windowsDrawn 时间戳计算
  • WaitTime:包含 AMS(ActivityManagerService)调度时间

WaitTime 包含系统调度开销(如 CPU 竞争),所以总是大于或等于TotalTime


BenchmarkRule

BenchmarkRule 是 Android Benchmark 库中的一个 JUnit 规则(@Rule),用于在 单元测试(JUnit4)环境下进行性能基准测试 。它能够测量代码片段的执行时间,并提供 抖动控制 和 精确的 CPU 时间测量 ,适用于 方法级别的性能评估。

使用要求

  • Android 10以上设备运行
  • 装机应用为release版本
  • 测试应用需要在Manifest里面声明:
xml 复制代码
 <application>
        <profileable android:shell="true"/>
</application>
  • 运行时需在主项目build.gradle指定 androidx.benchmark.junit4.AndroidBenchmarkRunner 作为 runner
gradle 复制代码
 android {
       defaultConfig {
       //testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 替换掉这个
        testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
       }
}
  • 运行设备要为 userdebug 模式,可 root

Macrobenchmark(宏基准测试)

在项目根目录 New -> Moudle 选择 benchmark 、Macrobenchmark ,Finsh 创建宏基准测试模块。

定义 宏基准测试主要关注整个应用程序或大部分应用功能的性能表现。它通常测试的是较大的操作或完整的业务流程,比如用户登录、数据加载、界面渲染等。

目的 衡量应用程序在真实使用场景下的总体性能,通常关注用户的整体体验。

示例 1.测试整个应用启动的时间。

  1. 测试一个完整的用户交互流程的响应时间,比如从点击按钮到完成操作的时间。
  2. 测试应用加载某个大数据集的性能。

当模块创建完毕后,会在清单文件自动生成

xml 复制代码
        <profileable
            android:shell="true"
            tools:targetApi="29" />

和主项目的build.gradle 中

gradle 复制代码
        benchmark {
            initWith release
            matchingFallbacks = ['release']
            signingConfig signingConfigs.release //++
        }

其中 signingConfig signingConfigs.release 是后面要加的,代表运行的时候指定签名配置。否则会报错: Exception thrown during onBeforeAll invocation of plugin AndroidTestApkInstallerPlugin: ErrorName: INSTALL_PARSE_FAILED_NO_CERTIFICATES

其他的配置不需要更改,benchmark 模块默认配置如下:

xml 复制代码
    buildTypes {
        // This benchmark buildType is used for benchmarking, and should function like your
        // release build (for example, with minification on). It's signed with a debug key
        // for easy local/CI testing.
        benchmark {
            debuggable = true
            signingConfig = debug.signingConfig
            matchingFallbacks = ["release"]
        }
    }

看别人的 debuggable 不能为true,不过我的为true好像也没什么影响。

启动测试

先打包release版本apk,安装进可 root 设备。接着在 benchmark 模块下的 ExampleStartupBenchmark 类中 启动 startup 方法,左边有个小箭头直接启动即可。

代码介绍如下:

java 复制代码
    @Test
    public void startup() {
        // 调用 mBenchmarkRule.measureRepeated 方法进行重复测量,记录应用启动性能
        mBenchmarkRule.measureRepeated(
                // 第一个参数是包名,指定测试的应用包名
                "com.example.quickdev",
                // 第二个参数是要收集的性能指标,这里使用的是 StartupTimingMetric 来度量启动时间
                Collections.singletonList(new StartupTimingMetric()),
                // 第三个参数是编译模式,DEFAULT 表示使用默认编译模式
                CompilationMode.DEFAULT,
                // 第四个参数是启动模式,COLD 表示冷启动,意味着应用从完全退出状态启动
                StartupMode.COLD,
                // 第五个参数是测量次数,这里指定了测量 5 次
                5,
                // 第六个参数是一个 Lambda 表达式,表示测量期间需要执行的操作
                scope -> {
                    // 按下 Home 键,模拟用户离开应用并返回桌面
                    scope.pressHome();
                    // 启动并等待指定应用,等待应用启动完成后再继续执行后续操作
                    scope.startActivityAndWait();
                    // 返回 null,表示操作执行完毕
                    return null;
                });
    }

冷启动测试结果

暖启动测试结果

热启动测试结果

可点击右侧测试次数的下标,点进去查看详细的测试信息,在第二张图的左上角可以查看cpu的消耗,左下找到当前应用行,查看代码具体耗时信息,右侧 Frames Chart可查看代码耗时火焰图展示书数据等。可以分析 CPU & 线程使用情况(避免 主线程阻塞)、查看火焰图,找到性能瓶颈(减少不必要的方法调用)

📊 BenchmarkRule vs. Macrobenchmark

  • BenchmarkRule → 方法级测试,适用于小型、局部代码性能分析(如字符串拼接、循环优化)。
  • Macrobenchmark → UI 级测试,适用于整个应用的性能分析(如 Activity 启动时间、RecyclerView 滚动性能)。
相关推荐
千里马学框架6 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台6 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone6 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc6 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo6 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077006 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼6 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone6 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen6 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone6 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui