Uygulamanızı Macrobenchmark'tan (Görünümler) kontrol etme

Kavramlar ve Jetpack Compose uygulaması

Çoğu Android kullanıcı arayüzü testinin aksine, makro karşılaştırma testleri uygulamanın kendisinden ayrı bir süreçte çalışır. Bu, uygulama sürecini durdurma ve DEX bayt kodundan makine diline derleme gibi işlemlerin etkinleştirilmesi için gereklidir.

UIAutomator kitaplığını veya hedef uygulamayı test sürecinden kontrol edebilen diğer mekanizmaları kullanarak uygulamanızın durumunu yönetebilirsiniz. Espresso veya ActivityScenario, uygulamayla paylaşılan bir süreçte çalışmayı beklediklerinden Macrobenchmark için kullanılamaz.

Aşağıdaki örnekte, kaynak kimliği kullanılarak bir RecyclerView bulunuyor ve birkaç kez aşağı kaydırılıyor:

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;
        }
    );
}

Karşılaştırmanızın kullanıcı arayüzünde kaydırma yapması gerekmez. Bunun yerine, örneğin bir animasyon çalıştırabilir. Ayrıca, özellikle UI Automator'ı kullanması da gerekmez. Kareler üretildiği sürece performans metrikleri toplanır.

Bazen uygulamanızın dışarıdan doğrudan erişilemeyen bölümlerini karşılaştırmak isteyebilirsiniz. Örneğin, exported=false ile işaretlenmiş iç Etkinliklere erişme, Fragment konumuna gitme veya kullanıcı arayüzünüzün bir bölümünü kaydırarak uzaklaştırma gibi işlemler yapabilirsiniz. Karşılaştırmaların, uygulamanın bu bölümlerine kullanıcı gibi manuel olarak gitmesi gerekir.

Manuel olarak gezinmek için setupBlock{} içindeki kodu, istediğiniz efekti (ör. düğmeye dokunma veya kaydırma) içerecek şekilde değiştirin. measureBlock{} yalnızca gerçekten karşılaştırmak istediğiniz kullanıcı arayüzü manipülasyonunu içeriyor:

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 -> {
            // ...
        }
    );
}