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

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

冷启动(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:通过 ActivityRecordwindowsDrawn 时间戳计算
  • WaitTime:包含 AMS(ActivityManagerService)调度时间

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


BenchmarkRule

BenchmarkRuleAndroid 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方法级测试,适用于小型、局部代码性能分析(如字符串拼接、循环优化)。
  • MacrobenchmarkUI 级测试,适用于整个应用的性能分析(如 Activity 启动时间、RecyclerView 滚动性能)。
相关推荐
来来走走16 分钟前
Flutter dart运算符
android·前端·flutter
青小莫35 分钟前
IDM下载失败常见原因
android
阿华的代码王国1 小时前
【Android】日期选择器
android·xml·java·前端·后端
小墙程序员3 小时前
Android 性能优化(五)Heap Dump 的使用
android·性能优化
阿华的代码王国3 小时前
【Android】RecyclerView实现新闻列表布局(1)适配器使用相关问题
android·xml·java·前端·后端
EngZegNgi3 小时前
Unity —— Android 应用构建与发布
android·unity·自动化·游戏引擎·构建
fatiaozhang95273 小时前
烽火HG680-KX-海思MV320芯片-2+8G-安卓9.0-强刷卡刷固件包
android·电视盒子·刷机固件·机顶盒刷机
LiuYaoheng4 小时前
【Android】使用 Intent 传递对象的两种序列化方式
android·java·笔记·学习
啊森要自信4 小时前
【MySQL 数据库】MySQL索引特性(二)页目录&&(B和B+树)&&(非)聚簇索引 && 索引操作
android·数据库·sql·mysql·adb·数据库架构
穷人小水滴5 小时前
Android 运行 deno 的新方法 (3): Termux 胖喵安初
android·linux