安卓启动 性能提升 20-30% ,基准配置 入门教程

1.先从官方下载demohttps://github.com/android/codelab-android-performance/archive/refs/heads/main.zip

2.先用Android studio打开里面的baseline-profiles项目

3.运行一遍app,这里建议用模拟器,(Pixel 6 API 34)设备运行,因为基准配置 需要root权限,如果手机没有root,就用模拟器运行。

4.运行时会报This version (1.4.5) of the Compose Compiler requires Kotlin version 1.8.20 but you appear to be using Kotlin version 1.9.22 which is not known to be compatible. Please consult the Compose-Kotlin compatibility map located at https://developer.android.com/jetpack/androidx/releases/compose-kotlin to choose a compatible version pair (or `suppressKotlinVersionCompatibilityCheck` but don't say I didn't warn you!).

5.修改libs.versions.toml里的 kotlin = "1.9.22" 改为 kotlin = "1.8.20"

6.再运行一下,private fun NavBackStackEntry.lifecycleIsResumed() = this.getLifecycle().currentState == Lifecycle.State.RESUMED 这里的getLifecycle()会报错,改成lifecycle

7.再运行一次,这一次应该可以启动成功了,图片不显示可以忽悠不管,因为这个图片是从谷歌那边加载过来的,需要飞机,我们重点是基准配置,如果前面步骤碰见其他问题,基本与该项目无关,可以自行百度和AI解决。

8.点击File->new module 选择baseline profile generator ,如图,如果你是java党,可以右边改改配置,因人而异,我这里就选择默认的kotlin,直接点finish

9.如果你碰见 配置文件一片红,就删除,重新创建,放app下面,就不会爆红了,如果你没有遇见以下问题,可以跳过此步

如果删不掉,是因为app在引用,把这段去掉,点击sync now,再重新删一下

10.在baselineprofile的build.gradle.kts文件中修改,添加代码如下,代码解释:useConnectedDevices = false意思是否在真机上运行,由于真机没有root,只能在模拟器上运行,所以选择false就行,然后配置模拟器 ,记得导入

复制代码
import com.android.build.api.dsl.ManagedVirtualDevice
Kotlin 复制代码
import com.android.build.api.dsl.ManagedVirtualDevice


android {

.......................
.......................
 targetProjectPath = ":app"
 testOptions.managedDevices.devices {
        create<ManagedVirtualDevice>("pixel6Api31") {
            device = "Pixel 6"
            apiLevel = 31
            systemImageSource = "aosp"
        }
    }
}


// This is the configuration block for the Baseline Profile plugin.
// You can specify to run the generators on a managed devices or connected devices.
baselineProfile {
    managedDevices += "pixel6Api31"

    useConnectedDevices = false
}

如图下

11.在baselineprofile找到BaselineProfileGenerator类,自己项目可以根据自己情况更改,但是由于我们是demo,就演示一下,代码如下

Kotlin 复制代码
  @Test
    fun generate() {
        // This example works only with the variant with application id `com.example.baselineprofiles_codelab`."
        rule.collect(
            packageName = "com.example.baselineprofiles_codelab",

            // See: https://d.android.com/topic/performance/baselineprofiles/dex-layout-optimizations
            includeInStartupProfile = true
        ) {
            // This block defines the app's critical user journey. Here we are interested in
            // optimizing for app startup. But you can also navigate and scroll through your most important UI.

            // Start default activity for your app
            pressHome()
            startActivityAndWait()

            // TODO Write more interactions to optimize advanced journeys of your app.
            // For example:
            // 1. Wait until the content is asynchronously loaded
            // 2. Scroll the feed content
            // 3. Navigate to detail screen
            // 1. Wait until the content is asynchronously loaded.
            waitForAsyncContent()
            // 2. Scroll the feed content.
            scrollSnackListJourney()
            // 3. Navigate to detail screen.
            goToSnackDetailJourney()

            // Check UiAutomator documentation for more information how to interact with the app.
            // https://d.android.com/training/testing/other-components/ui-automator
        }
    }

    fun MacrobenchmarkScope.waitForAsyncContent() {
        device.wait(Until.hasObject(By.res("snack_list")), 5_000)
        val contentList = device.findObject(By.res("snack_list"))
        // Wait until a snack collection item within the list is rendered.
        contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
    }

    fun MacrobenchmarkScope.scrollSnackListJourney() {
        val snackList = device.findObject(By.res("snack_list"))
        // Set gesture margin to avoid triggering gesture navigation.
        snackList.setGestureMargin(device.displayWidth / 5)
        snackList.fling(Direction.DOWN)
        device.waitForIdle()
    }

    fun MacrobenchmarkScope.goToSnackDetailJourney() {
        val snackList = device.findObject(By.res("snack_list"))
        val snacks = snackList.findObjects(By.res("snack_item"))
        // Select snack from the list based on running iteration.
        val index = (iteration ?: 0) % snacks.size
        snacks[index].click()
        // Wait until the screen is gone = the detail is shown.
        device.wait(Until.gone(By.res("snack_list")), 5_000)
    }

12.点击run按钮旁边三颗点,选择Edit Configurations...,然后点击左上角+,添加Gradle,在RUN下面一行添加:app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile,点击OK就行,然后运行,如图:

如果出现> 'compileNonMinifiedReleaseJavaWithJavac' task (current target is 1.8) and 'compileNonMinifiedReleaseKotlin' task (current target is 17) jvm target compatibility should be set to the same Java version.
Consider using JVM toolchain: https://kotl.in/gradle/jvm/toolchain

把compileOptions里的兼容版本改成对应的版本就行了,由于我是用的java 17,就改成17就行了,然后重新运行

复制代码
compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

如果没有出现上面问题,可以忽悠不管

13.运行大概需要等5-6分钟,如果太久了,建议重新运行一下,因设备而异,运行完成的话,在app项目的src->release->generated->baselineProfiles文件下,生成2个txt文件,一个是1.8W行-2.5W行的baseline-prof.txt文件和startup-prof.txt文件,因项目而异,如果基准配置更多,生成的可能更多,由于我们只生成了,异步加载,点击,滚动,差不多2W行

如图:

  1. 使用模拟器测试速度,在 baselineprofile 的 build.gradle.kts下的defaultConfig 里添加 testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "EMULATOR",代码解释,这段是用来印制模拟器的错误
复制代码
defaultConfig {
    minSdk = 28
    targetSdk = 34

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "EMULATOR"
}

15.在baselineprofile 项目的StartupBenchmarks类里添加和前面基准配置的 代码一样,模拟和基准操作

代码如下:

Kotlin 复制代码
  private fun benchmark(compilationMode: CompilationMode) {
        // This example works only with the variant with application id `com.example.baselineprofiles_codelab`."
        rule.measureRepeated(
            packageName = "com.example.baselineprofiles_codelab",
            metrics = listOf(StartupTimingMetric()),
            compilationMode = compilationMode,
            startupMode = StartupMode.COLD,
            iterations = 10,
            setupBlock = {
                pressHome()
            },
            measureBlock = {
                startActivityAndWait()

                waitForAsyncContent()
                // 2. Scroll the feed content.
                scrollSnackListJourney()
                // 3. Navigate to detail screen.
                goToSnackDetailJourney()
            }
        )
    }

    fun MacrobenchmarkScope.waitForAsyncContent() {
        device.wait(Until.hasObject(By.res("snack_list")), 5_000)
        val contentList = device.findObject(By.res("snack_list"))
        // Wait until a snack collection item within the list is rendered.
        contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
    }

    fun MacrobenchmarkScope.scrollSnackListJourney() {
        val snackList = device.findObject(By.res("snack_list"))
        // Set gesture margin to avoid triggering gesture navigation.
        snackList.setGestureMargin(device.displayWidth / 5)
        snackList.fling(Direction.DOWN)
        device.waitForIdle()
    }

    fun MacrobenchmarkScope.goToSnackDetailJourney() {
        val snackList = device.findObject(By.res("snack_list"))
        val snacks = snackList.findObjects(By.res("snack_item"))
        // Select snack from the list based on running iteration.
        val index = (iteration ?: 0) % snacks.size
        snacks[index].click()
        // Wait until the screen is gone = the detail is shown.
        device.wait(Until.gone(By.res("snack_list")), 5_000)
    }

16.然后,直接右键运行,这个测试类,在模拟器(Pixel 6 API 31) 以上运行,我建议在模拟器(Pixel 6 API 34)运行,因为API31,可能会报下面错误,如果出现了,就切到API34

如果出现了java.lang.IllegalStateException: Error: did not detect tracing on after 5000 ms ,我建议切换到模拟器(Pixel 6 API34),运行就不有问题17.运行效果如下

StartupBenchmarks_startupCompilationBaselineProfiles

timeToFullDisplayMs min 821.2, median 908.4, max 1,114.1

timeToInitialDisplayMs min 438.9, median 514.8, max 678.4

Traces: Iteration 0 1 2 3 4 5 6 7 8 9

Timed out waiting for process (com.example.baselineprofiles_codelab) to appear on Pixel_6_API_34 [emulator-5556].

WARNING: Running on Emulator

Benchmark is running on an emulator, which is not representative of

real user devices. Use a physical device to benchmark. Emulator

benchmark improvements might not carry over to a real user's

experience (or even regress real device performance).

StartupBenchmarks_startupCompilationNone

timeToFullDisplayMs min 984.5, median 1,157.2, max 1,257.2

timeToInitialDisplayMs min 498.9, median 606.3, max 668.4

Traces: Iteration 0 1 2 3 4 5 6 7 8 9

StartupBenchmarks_startupCompilationNone 表示没有基准上运行

StartupBenchmarks_startupCompilationBaselineProfiles表示在有基准上运行

1,157.2 ->908.4,提升大概200毫秒,差不多百分之20多,到这里教程就结束了,谢谢大家

相关推荐
韩楚风1 分钟前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
网络研究院15 分钟前
Android 安卓内存安全漏洞数量大幅下降的原因
android·安全·编程·安卓·内存·漏洞·技术
凉亭下22 分钟前
android navigation 用法详细使用
android
小比卡丘3 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭4 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
落落落sss5 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.6 小时前
数据库语句优化
android·数据库·adb
GEEKVIP8 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
长天一色9 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
model200510 小时前
android + tflite 分类APP开发-2
android·分类·tflite