ম্যাক্রোবেঞ্চমার্ক (ভিউস) থেকে আপনার অ্যাপ নিয়ন্ত্রণ করুন

ধারণা এবং জেটপ্যাক কম্পোজ বাস্তবায়ন

বেশিরভাগ অ্যান্ড্রয়েড UI টেস্টের মতো নয়, ম্যাক্রোবেঞ্চমার্ক টেস্টগুলো অ্যাপটি থেকে আলাদা একটি প্রসেসে চলে। অ্যাপ প্রসেস বন্ধ করা এবং DEX বাইটকোড থেকে মেশিন কোডে কম্পাইল করার মতো বিষয়গুলো সক্ষম করার জন্য এটি প্রয়োজনীয়।

আপনি UIAutomator লাইব্রেরি অথবা এমন অন্যান্য পদ্ধতি ব্যবহার করে আপনার অ্যাপের স্টেট নিয়ন্ত্রণ করতে পারেন, যা টেস্ট প্রসেস থেকে টার্গেট অ্যাপটিকে নিয়ন্ত্রণ করতে পারে। আপনি Macrobenchmark-এর জন্য Espresso বা ActivityScenario ব্যবহার করতে পারবেন না, কারণ এগুলো অ্যাপের সাথে একটি শেয়ার্ড প্রসেসে চলার প্রত্যাশা করে।

নিম্নলিখিত উদাহরণটি তার রিসোর্স আইডি ব্যবহার করে একটি RecyclerView খুঁজে বের করে এবং বেশ কয়েকবার নিচে স্ক্রল করে:

কোটলিন

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

    }
}

জাভা

@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 স্ক্রল করার প্রয়োজন নেই। এর পরিবর্তে, এটি একটি অ্যানিমেশন চালাতে পারে। এর জন্য বিশেষভাবে UI Automator ব্যবহার করারও প্রয়োজন নেই। যতক্ষণ ফ্রেম তৈরি হতে থাকে, ততক্ষণ এটি পারফরম্যান্স মেট্রিক সংগ্রহ করে।

কখনও কখনও আপনি আপনার অ্যাপের এমন অংশগুলির বেঞ্চমার্ক করতে চান যা বাইরে থেকে সরাসরি অ্যাক্সেসযোগ্য নয়। উদাহরণস্বরূপ, এটি হতে পারে exported=false দিয়ে চিহ্নিত করা ভেতরের অ্যাক্টিভিটিগুলি অ্যাক্সেস করা, একটি Fragment এ নেভিগেট করা, অথবা আপনার UI-এর কোনো অংশ সোয়াইপ করে সরিয়ে দেওয়া। বেঞ্চমার্কগুলির জন্য একজন ব্যবহারকারীর মতো করে অ্যাপের এই অংশগুলিতে ম্যানুয়ালি নেভিগেট করতে হয়।

ম্যানুয়ালি নেভিগেট করার জন্য, setupBlock{} এর ভেতরের কোডটি পরিবর্তন করে আপনার কাঙ্ক্ষিত ইফেক্ট (যেমন বাটন ট্যাপ বা সোয়াইপ) যোগ করুন। আপনার measureBlock{} এ শুধুমাত্র সেই UI ম্যানিপুলেশনটি থাকবে যা আপনি প্রকৃতপক্ষে বেঞ্চমার্ক করতে চান:

কোটলিন

@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()
    }
}

জাভা

@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 -> {
            // ...
        }
    );
}
{% হুবহু %} {% endverbatim %} {% হুবহু %} {% endverbatim %}