Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」2022 年 Google I/O 开发者大会上介绍了哪些 Android Jetpack 的最新变化?

前言

本系列文章从 Architecture,UI,Performance 和 Compose 这四个方向带大家了解本次 I/O 上 Jetpack 的最新内容。

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

本文是第二篇:Performance 篇。

1. JankStats 卡顿检测

JankStats 用来追踪和分析应用性能,发现 Jank 卡顿问题,它最低向下兼容到 API 16,可以在绝大多数机器设备上使用,有了它我们不必再求助 BlockCanery 等三方工具了。

implementation "androidx.metrics:metrics-performance:1.0.0-alpha01"

我们需要为每个 Window 创建一个 JankStats 实例,并通过 OnFrameListener 回调获取包含是否卡顿在内的帧信息,示例如下:

class JankLoggingActivity : AppCompatActivity() {

    private lateinit var jankStats: JankStats

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        // metricsStateHolder可以收集环境信息,跟随帧信息返回
        val metricsStateHolder = PerformanceMetricsState.getForHierarchy(binding.root)

        // 基于当前 Window 创建 JankStats 实例
        jankStats = JankStats.createAndTrack(
            window,
            Dispatchers.Default.asExecutor(),
            jankFrameListener,
        )

        // 设置 Activity 名字到环境信息
        metricsStateHolder.state?.addState("Activity", javaClass.simpleName)
        // ...
    }

    private val jankFrameListener = JankStats.OnFrameListener { frameData ->
        // 监听到的帧信息
        Log.v("JankStatsSample", frameData.toString())
    }
}

PerformanceMetricsState 用来收集你希望跟随 frameData 一起返回的状态信息,比如上面例子中设置了当前 Activity 名称,下面是 frameData 的打印日志:

JankStats.OnFrameListener: FrameData(frameStartNanos=827233150542009, frameDurationUiNanos=27779985, frameDurationCpuNanos=31296985, isJank=false, states=[Activity: JankLoggingActivity])

更多参考:medium.com/androiddeve…

2. Baseline Profiles 基准配置

Android 8.0 之后默认开启 ART 虚拟机。ART 最初版本在安装应用时会对全部代码进行 AOT 预编译,将字节码转换为机器码存在本地,这提升了运行时的速度,但是会导致安装过程变慢。因此后来 ART 改进为 JIT 和 AOT 相结合的方式,在应用安装时只将热点代码编译成机器码,缩短安装时间。

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

Baselin Profiles 基准配置文件允许我们配置哪些代码成为热点代码。基准配置文件将在 APK 的 assets/dexopt/baseline.prof 中编译为二进制形式,例如如果我们想提升首帧的性能,可以将应用启动或帧渲染期间使用的方法配置到 prof 文件中。

prof 文件可以通过自动或手动方式生成,我们可以编写 JUnit4 测试用例,通过执行 BaselineProfileRule 在测试中发现待优化的瓶颈代码,并生成对应的 prof 文件

@ExperimentalBaselineProfilesApi
@RunWith(AndroidJUnit4::class)
class BaselineProfileGenerator {
    @get:Rule val baselineProfileRule = BaselineProfileRule()

    @Test
    fun startup() =
        baselineProfileRule.collectBaselineProfile(packageName = "com.example.app") {
            pressHome()
            startActivityAndWait()
        }
}

我们也可以手动创建 prof 文件,只需遵循一些简单的语法规则。例如下面展示了 Jetpack Compose 库中包含的一些 Prof 规则,

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;

上述配置遵循 [FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE] 格式,其中 FLAGS 中的 H/S/P 代表方法的调用实际,比如是否是启动时调用等。

更多参考:android-developers.googleblog.com/2022/01/imp…

3. Benchmark 基准测试

Jetpack 当前提供了两套 Benchmark 库,Microbenchmark 和 Macrobenchmark (微基准和宏基准),分别用于不同场景下的基准测试。

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

Mircobenchmark 的测试对象是代码块,它的依赖如下:

androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.1.0-beta03'

我们可以在 JUnit4 中应用 BenchmarkRule,示例如下:

@RunWith(AndroidJUnit4::class)
class SampleBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()

    @Test
    fun benchmarkSomeWork() {
        benchmarkRule.measureRepeated {
            doSomeWork() //执行待测试代码
        }
    }
}

Macrobenchmark 通常面向更大粒度的场景测试,例如一个 Activity 启动或者一个用户操作等。由于 Macrobenchmark 不进行代码级别测试,我们可以创建独立于业务代码的单独模块进行测试:

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

下面展示了使用 MacrobenchmarkRule 测试一个 Activity 的启动:

    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = "mypackage.myapp",
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        startupMode = StartupMode.COLD
    ) { // this = MacrobenchmarkScope
        pressHome()
        val intent = Intent()
        intent.setPackage("mypackage.myapp")
        intent.setAction("mypackage.myapp.myaction")
        startActivityAndWait(intent)
    }

配合 2021.1.1 或更高版本的 Android Studio ,Benchmark 的测试结果会直接显示在 IDE 窗口中。

Google I/O :Android Jetpack 最新变化(二) Performance「终于解决」

当然,测试结果也可以导出为 JSON 格式

更多参考:medium.com/androiddeve…

4. Tracing 事件追踪

Tracing 用来在代码添加 trace 信息,trace 信息可以显示在 Systrace 和 Perfetto 等工具中。

implementation "androidx.tracing:tracing:1.1.0-beta01"

下面的例子汇总,我们通过 Trace 类的 benginSection/endSection 方法追踪 onCreateViewHolder 和 onBindViewHolder 方法执行的起始点

class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        return try {
            Trace.beginSection("MyAdapter.onCreateViewHolder")
            MyViewHolder.newInstance(parent)
        } finally {
            //endSection 放到 finally 里,当出现异常时也会调用
            Trace.endSection()
        }
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        Trace.beginSection("MyAdapter.onBindViewHolder")
        try {
            try {
                Trace.beginSection("MyAdapter.queryDatabase")
                val rowItem = queryDatabase(position)
                dataset.add(rowItem)
            } finally {
                Trace.endSection()
            }
            holder.bind(dataset[position])
        } finally {
            Trace.endSection()
        }
    }
}

需要注意 benginSection/endSection 必须成对出现,且必须在同一线程中。我们 Trace 的 section 会作为新增的自定义事件出现在 Perfetto 等工具视图中:

image.png

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13278.html

(0)

相关推荐

  • timestampdiff(oracle中timestamp)

    timestampdiff(oracle中timestamp)

    2023-10-01
    122
  • Python ID作为核心的开发

    Python ID作为核心的开发Python作为一种高级语言,广泛应用于各个领域。在Python开发过程中,IDE(集成开发环境)扮演着重要的角色,它可以提高开发效率和代码质量,让开发过程更加顺利。Python ID作为其中的一种,不仅具有语法高亮、自动缩进、自动补全等常用功能,还能够在一定程度上提升代码调试、测试和发布的效率。在本文中,我们将从多个方面对Python ID作为核心开发进行详细阐述。

    2024-04-14
    74
  • 星球元素logo_web3.0时代到来了吗

    星球元素logo_web3.0时代到来了吗越来越多的人对进军web3元宇宙充满着热情和野心,对于品牌来说,如何用wed3方式打造元宇宙星球的品牌?

    2023-06-29
    141
  • 学习MVC -第2部分:使用LINQ to SQL创建MVC应用程序和执行CRUD操作「建议收藏」

    学习MVC -第2部分:使用LINQ to SQL创建MVC应用程序和执行CRUD操作「建议收藏」下载PDF_Article.zip – 5.4 MB 下载SqlScriptToCreateTable.zip – 659 B 下载SqlScriptToCreateDatabase.zip – 1…

    2023-04-03
    152
  • mysql 实现表连接(左,右,内,全连接)【转】

    mysql 实现表连接(左,右,内,全连接)【转】查询中出现两个表的连接,下面通过实例来讲解一下各种连接查询的不同之处 表 a,和表b 如下图 a 表中 有 abcd b表中有 abcf 内连接: 得出结果 如图,选择等值的结果(abc) 左连接:

    2023-02-02
    164
  • 公众号迁移 原有数据库openid 更新主体openid[亲测有效]

    公众号迁移 原有数据库openid 更新主体openid[亲测有效] 今天一个两年前做的公众号项目 要更改主体,随之而来的是公众号的迁移。 公众号迁移后关注的粉丝也会对应的进行迁移,还会给粉丝发送相关通知。 大体流程如下图 迁移的具体步骤我就不细说了。今天主要…

    2023-03-21
    176
  • MySQL查看数据库表容量大小和磁盘空间占用大小

    MySQL查看数据库表容量大小和磁盘空间占用大小information_schema表 在MySQL中,把 information_schema 看作是一个信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库…

    2023-03-17
    154
  • Python中的list clear方法

    Python中的list clear方法在Python编程语言中,list是使用最广泛的数据类型之一。Python中的list对象类似于其他编程语言中的数组。Python中的list可以存储各种类型的数据,包括字符串、数字、对象等等。这些数据可以通过list的方法来进行增加、删除、修改和查询等操作。其中,list clear方法可以清空一个list,使得它变为一个空list,接下来我们将详细介绍Python中的list clear方法。

    2024-07-08
    44

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注