Restez organisé à l'aide des collections
Enregistrez et classez les contenus selon vos préférences.
Contrairement à la plupart des tests de l'interface utilisateur Android, les tests Macrobenchmark s'exécutent dans un processus distinct de l'appli elle-même. Cela est nécessaire pour permettre, entre autres, d'arrêter le processus de l'application et de compiler du bytecode DEX en code machine.
Vous pouvez contrôler l'état de votre application à l'aide de la bibliothèque UIAutomator ou d'autres mécanismes pouvant contrôler l'application cible à partir du processus de test.
Vous ne pouvez pas utiliser Espresso ni ActivityScenario pour Macrobenchmark, car ils doivent s'exécuter dans un processus partagé avec l'application.
L'exemple suivant trouve une RecyclerView à l'aide de son ID de ressource et fait défiler plusieurs fois vers le bas :
Kotlin
@TestfunscrollList(){benchmarkRule.measureRepeated(// ...setupBlock={// Before starting to measure, navigate to the UI to be measuredvalintent=Intent("$packageName.RECYCLER_VIEW_ACTIVITY")startActivityAndWait(intent)}){valrecycler=device.findObject(By.res(packageName,"recycler"))// Set gesture margin to avoid triggering gesture navigation// with input events from automation.recycler.setGestureMargin(device.displayWidth/5)// Scroll down several timesrepeat(3){recycler.fling(Direction.DOWN)}}}
@TestpublicvoidscrollList(){benchmarkRule.measureRepeated(// .../* setupBlock */scope->{// Before measuring, navigate to the UI to be measured.valintent=Intent("$packageName.RECYCLER_VIEW_ACTIVITY")scope.startActivityAndWait();returnUnit.INSTANCE;},/* measureBlock */scope->{UiDevicedevice=scope.getDevice();UiObject2recycler=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(inti=0;i<3;i++){recycler.fling(Direction.DOWN);}returnUnit.INSTANCE;});}
Votre benchmark n'a pas besoin de faire défiler l'interface utilisateur. À la place, il peut par exemple exécuter une animation. Il n'a pas non plus besoin d'utiliser UIAutomator en particulier. Il collecte des métriques de performances tant que les frames sont produits par le système de vues, qui comprend les frames produits par Jetpack Compose.
Accéder aux parties internes de l'application
Vous pouvez parfois comparer des parties de votre application qui ne sont pas directement accessibles de l'extérieur. Il peut s'agir, par exemple, d'accéder à des activités internes marquées de exported=false, d'accéder à un Fragment ou de balayer une partie de votre interface utilisateur pour la faire disparaître. Les benchmarks doivent accéder manuellement à ces parties de l'application, comme le ferait un utilisateur.
Pour naviguer manuellement, modifiez le code dans setupBlock{} pour contenir l'effet souhaité, par exemple un appui sur un bouton ou un balayage. Votre measureBlock{} ne contient que la manipulation de l'interface utilisateur que vous souhaitez comparer :
Kotlin
@TestfunnonExportedActivityScrollList(){benchmarkRule.measureRepeated(// ...setupBlock=setupBenchmark()){// ...}}privatefunsetupBenchmark():MacrobenchmarkScope.()->Unit={// Before starting to measure, navigate to the UI to be measuredstartActivityAndWait()// click a button to launch the target activity.// While we use button text here to find the button, you could also use// accessibility info or resourceId.valselector=By.text("RecyclerView")if(!device.wait(Until.hasObject(selector),5_500)){fail("Could not find resource in time")}vallaunchRecyclerActivity=device.findObject(selector)launchRecyclerActivity.click()// wait until the activity is showndevice.wait(Until.hasObject(By.clazz("$packageName.NonExportedRecyclerActivity")),TimeUnit.SECONDS.toMillis(10))}
@TestpublicvoidscrollList(){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.UiObject2launchRecyclerActivity=scope.getDevice().findObject(By.res(packageName,"launchRecyclerActivity"))launchRecyclerActivity.click();// Wait until activity is shown.scope.getDevice().wait(Until.hasObject(By.clazz("$packageName.NonExportedRecyclerActivity")),10000L)returnUnit.INSTANCE;},/* measureBlock */scope->{// ...});}
Recommandations personnalisées
Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
Le contenu et les exemples de code de cette page sont soumis aux licences décrites dans la Licence de contenu. Java et OpenJDK sont des marques ou des marques déposées d'Oracle et/ou de ses sociétés affiliées.
Dernière mise à jour le 2025/09/09 (UTC).
[[["Facile à comprendre","easyToUnderstand","thumb-up"],["J'ai pu résoudre mon problème","solvedMyProblem","thumb-up"],["Autre","otherUp","thumb-up"]],[["Il n'y a pas l'information dont j'ai besoin","missingTheInformationINeed","thumb-down"],["Trop compliqué/Trop d'étapes","tooComplicatedTooManySteps","thumb-down"],["Obsolète","outOfDate","thumb-down"],["Problème de traduction","translationIssue","thumb-down"],["Mauvais exemple/Erreur de code","samplesCodeIssue","thumb-down"],["Autre","otherDown","thumb-down"]],["Dernière mise à jour le 2025/09/09 (UTC)."],[],[],null,["# Control your app from Macrobenchmark\n\nUnlike most Android UI tests, Macrobenchmark tests run in a separate process\nfrom the app itself. This is necessary to enable things like stopping the\napp process and compiling from DEX bytecode to machine code.\n\nYou can drive your app's state using the [UIAutomator library](/training/testing/ui-automator) or other\nmechanisms that can control the target app from the test process.\nYou can't use [Espresso](/training/testing/espresso) or [`ActivityScenario`](/reference/androidx/test/core/app/ActivityScenario) for\nMacrobenchmark because they expect to run in a shared process with the app.\n\nThe following example finds a [`RecyclerView`](/reference/androidx/recyclerview/widget/RecyclerView) using its resource ID and\nscrolls down several times: \n\n### Kotlin\n\n```kotlin\n@Test\nfun scrollList() {\n benchmarkRule.measureRepeated(\n // ...\n setupBlock = {\n // Before starting to measure, navigate to the UI to be measured\n val intent = Intent(\"$packageName.RECYCLER_VIEW_ACTIVITY\")\n startActivityAndWait(intent)\n }\n ) {\n val recycler = device.findObject(By.res(packageName, \"recycler\"))\n // Set gesture margin to avoid triggering gesture navigation\n // with input events from automation.\n recycler.setGestureMargin(device.displayWidth / 5)\n\n // Scroll down several times\n repeat(3) { recycler.fling(Direction.DOWN) }\n }\n}https://github.com/android/performance-samples/blob/570221d3f49d49e45af7970c04c1fe3a72d6df33/MacrobenchmarkSample/macrobenchmark/src/main/java/com/example/macrobenchmark/benchmark/frames/FrameTimingBenchmark.kt#L44-L70\n```\n\n### Java\n\n```java\n@Test\npublic void scrollList() {\n benchmarkRule.measureRepeated(\n // ...\n /* setupBlock */ scope -\u003e {\n // Before measuring, navigate to the UI to be measured.\n val intent = Intent(\"$packageName.RECYCLER_VIEW_ACTIVITY\")\n scope.startActivityAndWait();\n return Unit.INSTANCE;\n },\n /* measureBlock */ scope -\u003e {\n UiDevice device = scope.getDevice();\n UiObject2 recycler = device.findObject(By.res(scope.getPackageName(), \"recycler\"));\n\n // Set gesture margin to avoid triggering gesture navigation\n // with input events from automation.\n recycler.setGestureMargin(device.getDisplayWidth() / 5);\n\n // Fling the recycler several times.\n for (int i = 0; i \u003c 3; i++) {\n recycler.fling(Direction.DOWN);\n }\n\n return Unit.INSTANCE;\n }\n );\n}\n```\n\nYour benchmark doesn't have to scroll the UI. Instead, it can run an\nanimation, for example. It also doesn't need to use UI Automator\nspecifically. It collects performance metrics as long as frames are being\nproduced by the view system, including frames produced by [Jetpack Compose](/jetpack/compose).\n| **Note:** When accessing UI objects, specify the `packageName`, because the tests run in a separate process.\n\nNavigate to internal parts of the app\n-------------------------------------\n\nSometimes you want to benchmark parts of your app that aren't directly\naccessible from outside. This might be, for example, accessing inner Activities\nthat are marked with [`exported=false`](/guide/topics/manifest/activity-element#exported), navigating to a [`Fragment`](/reference/android/app/Fragment), or swiping\nsome part of your UI away. The benchmarks need to manually navigate to these\nparts of the app like a user.\n\nTo manually navigate, change the code inside `setupBlock{}` to contain the\neffect you want, such as button tap or swipe. Your `measureBlock{}` contains\nonly the UI manipulation you want to actually benchmark: \n\n### Kotlin\n\n```kotlin\n@Test\nfun nonExportedActivityScrollList() {\n benchmarkRule.measureRepeated(\n // ...\n setupBlock = setupBenchmark()\n ) {\n // ...\n }\n}\n\nprivate fun setupBenchmark(): MacrobenchmarkScope.() -\u003e Unit = {\n // Before starting to measure, navigate to the UI to be measured\n startActivityAndWait()\n\n // click a button to launch the target activity.\n // While we use button text here to find the button, you could also use\n // accessibility info or resourceId.\n val selector = By.text(\"RecyclerView\")\n if (!device.wait(Until.hasObject(selector), 5_500)) {\n fail(\"Could not find resource in time\")\n }\n val launchRecyclerActivity = device.findObject(selector)\n launchRecyclerActivity.click()\n\n // wait until the activity is shown\n device.wait(\n Until.hasObject(By.clazz(\"$packageName.NonExportedRecyclerActivity\")),\n TimeUnit.SECONDS.toMillis(10)\n )\n}https://github.com/android/performance-samples/blob/570221d3f49d49e45af7970c04c1fe3a72d6df33/MacrobenchmarkSample/macrobenchmark/src/main/java/com/example/macrobenchmark/benchmark/frames/NonExportedActivityBenchmark.kt#L48-L94\n```\n\n### Java\n\n```java\n@Test\npublic void scrollList() {\n benchmarkRule.measureRepeated(\n // ...\n /* setupBlock */ scope -\u003e {\n // Before measuring, navigate to the default activity.\n scope.startActivityAndWait();\n\n // Click a button to launch the target activity.\n // While you use resourceId here to find the button, you can also\n // use accessibility info or button text content.\n UiObject2 launchRecyclerActivity = scope.getDevice().findObject(\n By.res(packageName, \"launchRecyclerActivity\")\n )\n launchRecyclerActivity.click();\n\n // Wait until activity is shown.\n scope.getDevice().wait(\n Until.hasObject(By.clazz(\"$packageName.NonExportedRecyclerActivity\")),\n 10000L\n )\n\n return Unit.INSTANCE;\n },\n /* measureBlock */ scope -\u003e {\n // ...\n }\n );\n}\n```\n\nRecommended for you\n-------------------\n\n- Note: link text is displayed when JavaScript is off\n- [Writing a Macrobenchmark](/topic/performance/benchmarking/macrobenchmark-overview)\n- [Capture Macrobenchmark metrics](/topic/performance/benchmarking/macrobenchmark-metrics)\n- [Microbenchmark](/topic/performance/benchmarking/microbenchmark-overview)"]]