安卓启动 性能提升 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多,到这里教程就结束了,谢谢大家

相关推荐
coderlin_7 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
2501_915918418 小时前
Fiddler中文版全面评测:功能亮点、使用场景与中文网资源整合指南
android·ios·小程序·https·uni-app·iphone·webview
wen's9 小时前
React Native安卓刘海屏适配终极方案:仅需修改 AndroidManifest.xml!
android·xml·react native
编程乐学10 小时前
网络资源模板--基于Android Studio 实现的聊天App
android·android studio·大作业·移动端开发·安卓移动开发·聊天app
EndingCoder11 小时前
搜索算法在前端的实践
前端·算法·性能优化·状态模式·搜索算法
没有了遇见12 小时前
Android 通过 SO 库安全存储敏感数据,解决接口劫持问题
android
hsx66612 小时前
使用一个 RecyclerView 构建复杂多类型布局
android
hsx66612 小时前
利用 onMeasure、onLayout、onDraw 创建自定义 View
android
守城小轩12 小时前
Chromium 136 编译指南 - Android 篇:开发工具安装(三)
android·数据库·redis
whysqwhw13 小时前
OkHttp平台抽象机制分析
android