Android性能优化 | DEX 布局优化和启动配置文件
引言
使用DEX布局优化和启动配置文件是优化Android应用性能的有效途径。DEX布局优化可以通过优化应用程序中的DEX文件布局,从而加快Android应用的启动速度和执行速度。启动配置文件则提供了一种灵活的方式来控制应用程序的启动流程和加载顺序,从而更好地优化应用程序的性能。
要使用DEX布局优化和启动配置文件,首先需要安装Jetpack Macrobenchmarks版本1.2.0-alpha14或更高版本,并确保Android Gradle插件(基准配置文件、DEX布局优化以及改进了配置文件编译)的版本符合最低要求。其次,为了简化设置,建议使用基准配置文件Gradle插件。
https://maven.google.com/web/index.html?q=benchmark&hl=zh-cn#androidx.benchmark:benchmark-macro-junit4:1.2.0-alpha14
使用启动配置文件进行DEX布局优化是一项实验性功能,需要添加实验性标记。为了获得最佳性能,还需要在应用程序代码中进行一些必要的修改。同时,请注意目前不支持使用第三方构建系统如Bazel等。
启动配置文件
启动配置文件与基准配置文件类似,都是描述应用程序中关键类和方法的配置文件。但是,启动配置文件不同于基准配置文件的地方在于,启动配置文件主要描述了应用程序启动时至关重要的类和方法。这些类和方法必须先做好加载准备,以保证应用程序能够快速启动。
需要注意的是,应用程序启动通常是多个关键用户历程 (CUJ) 的组合。因此,在启动配置文件中,可以定义这些关键 CUJ,并确定它们的加载顺序和执行流程。同时,启动配置文件还需使用人类可读格式 (HRF),与基准配置文件相同。
与基准配置文件不同的是,启动配置文件无法由库提供,也不受 Android Gradle 插件合并的约束。这是因为库不一定充分了解应用启动的关键类和方法有哪些。因此,在编写启动配置文件时,最好由 Jetpack Macrobenchmark 衍生,并与专门针对应用启动的 CUJ 结合使用。此外,在基准配置文件中,除了应用启动外的其他优化也会被包含进去,例如减少动画期间或应用启动以外的关键用户历程 (CUJ) 期间的卡顿。
最后,需要注意的是,启动配置文件存储在 src/<variantName>/main/baselineProfiles/startup-prof.txt
中。因此,在进行 DEX 布局优化时,需要确保存储位置正确,并且与专门针对应用启动的 CUJ 结合使用,从而达到最佳优化效果。
DEX 布局优化
通过优化应用程序中的 DEX 文件布局,可以显著加快 Android 应用的启动速度和执行速度。这一优化措施的主要目标是减少应用启动期间发生的主要页面故障的数量,提高用户体验。
具体而言,这项优化的核心思想是将启动期间要执行的所有代码添加到主要 classes.dex 文件中,同时将所有非启动代码从主要 classes.dex 文件中移除。这样做的好处在于,启动时需要加载的代码量将大大减少,从而可以降低启动时间并提升性能。
值得注意的是,这一优化措施并非简单地将所有代码都放入一个 DEX 文件中,而是需要根据应用程序的具体情况来进行调整。通过合理规划 DEX 文件布局,可以根据不同的场景和需求,将代码分配到多个 DEX 文件中,并优化其加载顺序和执行流程。
使用 DEX 布局优化
接下来讲述如何使用DEX布局优化
构建启动配置文件
首先,您需要创建一个启动配置文件。
在项目设置方面,在前面的示例中,我们以一个名为com.example.app
的app模块为例进行了插桩测试。
当您使用Jetpack Macrobenchmark生成启动配置文件规则时,您需要在build.gradle
文件中定义一个新的基准变体。这个基准变体与发布变体相似,但您需要关闭缩减功能。
项目设置
以下是取自应用模块的build.gradle文件的代码示例:
buildTypes {
...
create("benchmark") {
initWith(buildTypes.getByName("release")
isMinifyEnabled = false
signingConfig = signingConfigs.getByName("debug")
matchingFallbacks += "release"
}
}
生成启动规则
@RunWith(AndroidJUnit4::class)
class StartupProfileGenerator {
@get:Rule
val baselineProfileRule = BaselineProfileRule()
@Test
fun startup() =
baselineProfileRule.collect(
packageName = "com.example.app",
includeInStartupProfile = true
) {
// This scenario just starts the activity and waits for it to draw
// the first frame. If you have animations or async content in your
// startup, wait for them with UiAutomator.
startActivityAndWait()
}
}
运行测试会输出下面内容:
HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;
将输出文件的内容复制到 src/main/baselineProfiles/startup-prof.txt
。
启用 DEX 布局优化
Android提供了实验性属性 android.experimental.r8.dex-startup-optimization
,以支持DEX布局优化。
需要注意的是,启用此标记后,主要 DEX 文件将只包含应用启动所需的类,这可以显著减少启动时间并提升性能。但如果您的应用程序之前从未使用过MultiDex,则现在需要启用MultiDex功能。
因此,在启用android.experimental.r8.dex-startup-optimization
属性时,需要确保您的应用程序已经配置好MultiDex
,并且所有相关类和方法都已正确分配到各个DEX文件中。这样才能确保您的应用程序在启动时获得最佳效果。
android {
// ...
experimentalProperties["android.experimental.r8.dex-startup-optimization"] = true
}
构建具有 DEX 布局优化功能的 APK
./gradlew :app:assembleRelease
结论
总的来说,使用DEX布局优化和启动配置文件是优化Android应用性能的有力工具,可以显著提升应用程序的启动速度和执行效率。但在使用时需要注意相关版本和设置的要求,以确保获得最佳效果。