与大多数 Android 界面测试不同,Macrobenchmark 测试在独立于应用本身的进程中运行。必须这样做才能实现停止应用进程和从 DEX 字节码编译到机器码等目的。
您可以使用 UIAutomator 库或其他可以在测试进程中控制目标应用的机制来驱动应用的状态。您不能将 Espresso 或 ActivityScenario 用于 Macrobenchmark,因为它们需要在与应用共享的进程中运行。
以下示例会使用资源 ID 查找 RecyclerView,然后向下滚动几次:
Kotlin
@Test fun scrollList() { benchmarkRule.measureRepeated( // ... setupBlock = { uiAutomator { // Before starting to measure, navigate to the UI to be measured startIntent(Intent("$packageName.RECYCLER_VIEW_ACTIVITY")) } } ) { uiAutomator { val recycler = onElement { className == "androidx.recyclerview.widget.RecyclerView" } // Scroll down several times repeat(3) { recycler.fling(Direction.DOWN) } } } }
Java
@Test public void scrollList() { benchmarkRule.measureRepeated( // ... /* setupBlock */ scope -> { // Before measuring, navigate to the UI to be measured. val intent = Intent("$packageName.RECYCLER_VIEW_ACTIVITY") scope.startActivityAndWait(); return Unit.INSTANCE; }, /* measureBlock */ scope -> { UiDevice device = scope.getDevice(); UiObject2 recycler = device.findObject(By.res(scope.getPackageName(), "recycler")); // Set gesture margin to avoid triggering gesture navigation // with input events from automation. recycler.setGestureMargin(device.getDisplayWidth() / 5); // Fling the recycler several times. for (int i = 0; i < 3; i++) { recycler.fling(Direction.DOWN); } return Unit.INSTANCE; } ); }
基准测试并不一定要滚动界面。不过,举例来说,它可以运行动画。此外,它也不需要特地使用 UI Automator。只要帧是由视图系统生成的(其中包括 Jetpack Compose 生成的帧),基准测试就会收集性能指标。
进入应用的内部板块
有时,您需要对应用中无法直接从外部访问的板块进行基准测试。例如,您可能需要访问内部 activity(标有 exported=false)、进入 Fragment,或者滑开界面的某个部分。基准测试需要像用户一样手动进入应用的这些板块。
如需手动进入相应板块,请更改 setupBlock{} 内的代码以包含所需的效果,例如按钮点按或滑动。您的 measureBlock{} 仅包含您要实际进行基准测试的界面操作:
Kotlin
@Test fun nonExportedActivityScrollList() { benchmarkRule.measureRepeated( // ... setupBlock = setupBenchmark() ) { // ... } } private fun setupBenchmark(): MacrobenchmarkScope.() -> Unit = { uiAutomator { // Before starting to measure, navigate to the UI to be measured startApp(TARGET_PACKAGE) // click a button to launch the target activity. onElement { textAsString() == "RecyclerView" }.click() // wait until the activity is shown waitForStableInActiveWindow() } }
Java
@Test public void scrollList() { benchmarkRule.measureRepeated( // ... /* setupBlock */ scope -> { // Before measuring, navigate to the default activity. scope.startActivityAndWait(); // Click a button to launch the target activity. // While you use resourceId here to find the button, you can also // use accessibility info or button text content. UiObject2 launchRecyclerActivity = scope.getDevice().findObject( By.res(packageName, "launchRecyclerActivity") ) launchRecyclerActivity.click(); // Wait until activity is shown. scope.getDevice().wait( Until.hasObject(By.clazz("$packageName.NonExportedRecyclerActivity")), 10000L ) return Unit.INSTANCE; }, /* measureBlock */ scope -> { // ... } ); }
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 编写 Macrobenchmark
- 捕获 Macrobenchmark 指标
- Microbenchmark