You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Macrobenchmark执行失败:By.res返回Null触发空指针异常

解决Jetpack Macrobenchmark中UiAutomator选择器空指针问题

问题场景

学习Jetpack Benchmark时,参考官方示例实现clickOnId方法,调用时传入"launchRecyclerActivity"触发空指针异常,报错显示找不到对应UI元素。

相关代码

  1. 自定义的clickOnId方法:
private fun MacrobenchmarkScope.clickOnId(resourceId: String) {
        val selector = By.res(packageName, resourceId)
        if (!device.wait(Until.hasObject(selector), 2_500)) {
            fail("Did not find object with id $resourceId")
        }

        device
            .findObject(selector)
            .click()
        // Chill to ensure we capture the end of the click span in the trace.
        Thread.sleep(100)
    }
  1. 字符串资源定义:
<string name="launchRecyclerActivity">RecyclerView</string>
  1. 对应Compose组件:
BenchmarkActivityButton(name = "RecyclerView") {
            launchActivityWithTrace<NonExportedRecyclerActivity>()
        }

@Composable
    fun BenchmarkActivityButton(name: String, onClick: () -> Unit) {
        TextButton(
            modifier = Modifier.padding(8.dp),
            onClick = onClick,
            border = BorderStroke(1.dp, MaterialTheme.colors.primary)
        ) {
            Text(name)
        }
    }
  1. 异常信息:
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.test.uiautomator.UiObject2.click()' on a null object reference
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.clickOnId(ClickLatencyBenchmark.kt:189)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.access$clickOnId(ClickLatencyBenchmark.kt:40)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark$simpleViewClick$2.invoke(ClickLatencyBenchmark.kt:64)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark$simpleViewClick$2.invoke(ClickLatencyBenchmark.kt:51)
at androidx.benchmark.macro.MacrobenchmarkKt$macrobenchmark$measurements$1$tracePath$1.invoke(Macrobenchmark.kt:193)
at androidx.benchmark.macro.MacrobenchmarkKt$macrobenchmark$measurements$1$tracePath$1.invoke(Macrobenchmark.kt:167)
at androidx.benchmark.perfetto.PerfettoCaptureWrapper.record(PerfettoCaptureWrapper.kt:90)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmark(Macrobenchmark.kt:167)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmarkWithStartupMode(Macrobenchmark.kt:301)
at androidx.benchmark.macro.junit4.MacrobenchmarkRule.measureRepeated(MacrobenchmarkRule.kt:106)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.simpleViewClick(ClickLatencyBenchmark.kt:51)

核心原因

混淆了字符串资源的name和UiAutomator定位所需的View资源ID:传入的"launchRecyclerActivity"是字符串资源的name,但By.res()方法需要的是UI元素的唯一资源ID(不是显示文本对应的字符串资源)。当前Compose按钮没有设置可被UiAutomator识别的资源ID,导致选择器找不到元素,最终触发空指针。

解决步骤

1. 给Compose按钮设置可识别的定位标识

对于Compose组件,有两种常用方式让UiAutomator能定位到元素:

方式一:使用TestTag配合语义配置

在Compose按钮上添加testTag,同时开启testTagsAsResourceId,让TestTag被当作资源ID识别:

@Composable
fun BenchmarkActivityButton(name: String, onClick: () -> Unit) {
    TextButton(
        modifier = Modifier
            .padding(8.dp)
            .semantics {
                testTagsAsResourceId = true // 开启TestTag作为资源ID
                testTag = "launchRecyclerActivity" // 设置和调用时一致的标识
            },
        onClick = onClick,
        border = BorderStroke(1.dp, MaterialTheme.colors.primary)
    ) {
        Text(name)
    }
}

方式二:使用资源ID(推荐规范写法)

  • 首先在res/values/ids.xml中定义一个唯一的View资源ID:
<item name="btn_launch_recycler_activity" type="id"/>
  • 然后在Compose组件中绑定该ID:
@Composable
fun BenchmarkActivityButton(name: String, onClick: () -> Unit) {
    TextButton(
        modifier = Modifier
            .padding(8.dp)
            .semantics {
                testTagsAsResourceId = true
                testTag = stringResource(R.id.btn_launch_recycler_activity)
            },
        onClick = onClick,
        border = BorderStroke(1.dp, MaterialTheme.colors.primary)
    ) {
        Text(name)
    }
}
  • 调用clickOnId时传入这个ID的字符串形式:
clickOnId("btn_launch_recycler_activity")

2. 验证元素定位正确性

使用Android SDK自带的uiautomatorviewer工具(路径:Android SDK/tools/bin/uiautomatorviewer),连接设备后捕获当前界面,查看按钮元素的resource-id属性,确认是否和你设置的标识一致。

3. 优化等待时间(可选)

如果界面加载较慢,2500ms的等待时间可能不足以让元素出现,可以适当延长等待时长,比如改为5000ms:

if (!device.wait(Until.hasObject(selector), 5_000)) {
    fail("Did not find object with id $resourceId")
}

内容的提问来源于stack exchange,提问作者Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 01:31:19