Performa dan hierarki tampilan

Cara mengelola hierarki objek View dapat berdampak besar pada performa aplikasi Anda. Halaman ini menjelaskan cara menilai apakah hierarki tampilan memperlambat aplikasi Anda, dan menawarkan beberapa strategi untuk mengatasi masalah yang mungkin terjadi.

Performa tata letak dan pengukuran

Pipeline rendering meliputi tahap tata letak dan pengukuran, di mana sistem secara tepat memosisikan item yang relevan dalam hierarki tampilan Anda. Bagian pengukuran pada tahap ini menentukan ukuran dan batas objek View. Bagian tata letak menentukan posisi objek View di layar.

Kedua tahap pipeline ini menimbulkan sedikit biaya per tampilan atau tata letak yang diproses. Biasanya, biaya ini tidak besar dan tidak terlalu memengaruhi performa. Namun, lebih baik lagi jika aplikasi menambahkan atau menghapus objek View seperti saat objek RecyclerView mendaur ulang atau menggunakannya kembali. Biaya tersebut juga dapat lebih tinggi jika objek View perlu mempertimbangkan perubahan ukuran mempertahankan batasannya: Misalnya, jika aplikasi Anda memanggil SetText() pada objek View yang menggabungkan teks, maka View perlu diubah ukurannya.

Jika hal ini memakan waktu terlalu lama, proses ini dapat mencegah frame untuk tidak melakukan proses rendering dalam 16 milidetik yang diperbolehkan, sehingga frame akan dibuang, dan animasi menjadi tersendat.

Karena Anda tidak dapat memindahkan operasi ini ke thread pekerja, aplikasi Anda harus memprosesnya di thread utama, langkah terbaiknya adalah dengan mengoptimalkannya agar menghemat waktu kerja seefektif mungkin.

Mengelola kompleksitas: masalah tata letak

Tata letak Android memungkinkan Anda menyarangkan objek UI di hierarki tampilan. Penyarangan (nesting) ini juga dapat menimbulkan biaya tata letak. Jika aplikasi Anda memproses objek untuk tata letak, aplikasi tersebut akan melakukan proses yang sama pada semua turunan tata letak. Untuk tata letak yang rumit, terkadang biaya hanya muncul saat sistem menghitung tata letak untuk pertama kali. Misalnya, saat aplikasi Anda mendaur ulang item daftar yang kompleks dalam objek RecyclerView, sistem tersebut perlu membuat tata letak semua objek tersebut. Dalam contoh lain, perubahan trivial dapat menyebarkan rantai ke arah induk sampai mencapai objek yang tidak memengaruhi ukuran induk.

Kasus paling umum di mana tata letak memerlukan waktu yang sangat lama adalah saat hierarki objek View bersarang satu sama lain. Setiap objek tata letak bersarang menambahkan biaya ke tahapan tata letak. Semakin datar hierarki Anda, semakin sedikit waktu yang dibutuhkan untuk menyelesaikan tahapan tata letak.

Jika Anda menggunakan class RelativeLayout, Anda mungkin dapat mendapatkan efek yang sama, dengan biaya yang lebih rendah, menggunakan tampilan LinearLayout bersarang dan tidak tertimbang. Selain itu, jika aplikasi Anda menargetkan Android 7.0 (API level 24), kemungkinan Anda dapat menggunakan editor tata letak khusus untuk membuat objek ConstraintLayout, bukan RelativeLayout. Hal tersebut memungkinkan Anda untuk menghindari berbagai masalah yang dijelaskan di bagian ini. Class ConstraintLayout menawarkan kontrol tata letak yang serupa, tetapi dengan performa yang jauh lebih baik. Class ini menggunakan sistem penyelesaian kendala sendiri untuk mengatasi hubungan antara tampilan dengan cara yang sangat berbeda dari tata letak standar.

Taksasi ganda

Biasanya, framework akan mengeksekusi tata letak atau tahapan pengukuran dalam satu pass dan dalam waktu yang cukup cepat. Namun, dengan adanya beberapa kasus tata letak yang lebih rumit, framework mungkin harus melakukan iterasi beberapa kali pada bagian-bagian hierarki yang memerlukan beberapa pass untuk diselesaikan sebelum akhirnya menempatkan elemen. Keharusan untuk melakukan satu atau beberapa iterasi tata letak dan pengukuran disebut sebagai taksasi ganda.

Misalnya, saat Anda menggunakan penampung RelativeLayout, yang memungkinkan Anda untuk memosisikan objek View sehubungan dengan posisi objek View yang lain, framework akan melakukan tindakan berikut:

  1. Mengeksekusi pass tata letak dan pengukuran, di mana framework akan menghitung masing-masing posisi dan ukuran objek turunan sesuai dengan permintaan setiap turunan.
  2. Menggunakan data ini, yang juga mempertimbangkan bobot objek, untuk mengetahui posisi yang tepat dari tampilan terkait.
  3. Melakukan pass tata letak kedua untuk menyelesaikan posisi objek.
  4. Melanjutkan ke tahap selanjutnya dari proses rendering.

Semakin banyak level hierarki tampilan yang Anda miliki, semakin besar kemungkinan penalti performanya.

Container selain RelativeLayout juga dapat meningkatkan taksasi ganda. Contoh:

  • Tampilan LinearLayout dapat menghasilkan pass tata letak dan pengukuran ganda jika dibuat horizontal. Pass tata letak dan pengukuran ganda juga dapat muncul pada orientasi vertikal jika Anda menambahkan measureWithLargestChild, yang mana framework mungkin perlu melakukan pass kedua untuk mengatasi ukuran objek yang tepat.
  • GridLayout memiliki masalah yang serupa. Container ini juga memungkinkan pemosisian relatif, yang normalnya akan menghindari taksasi ganda dengan memproses lebih dahulu hubungan posisi di antara tampilan turunan. Namun, jika tata letak menggunakan bobot atau mengisinya dengan class Gravity, manfaat pemrosesan tersebut akan hilang, sehingga framework mungkin harus melakukan beberapa pass jika container-nya adalah RelativeLayout.

Beberapa pass tata letak dan pengukuran bukan dengan sendirinya berupa beban performa. Namun, pass ini dapat menjadi beban performa jika letaknya ada di tempat yang salah. Anda harus waspada terhadap situasi jika salah satu kondisi berikut berlaku pada container Anda:

  • Merupakan elemen root dalam hierarki tampilan Anda.
  • Memiliki hierarki tampilan yang mendalam di bawahnya.
  • Ada banyak instance yang mengisi layar, mirip dengan turunan dalam objek ListView.

Mendiagnosis masalah hierarki tampilan

Performa tata letak merupakan masalah yang kompleks dengan banyak faset. Ada beberapa fitur yang dapat memberi Anda indikasi kuat tentang lokasi kemunculan bottleneck performa. Beberapa fitur lain memberikan informasi yang kurang pasti, tetapi juga dapat memberikan petunjuk yang berguna.

Systrace

Salah satu alat yang menyediakan data terbaik terkait performa adalah Systrace, yang di-build ke dalam SDK Android. Alat Systrace memungkinkan Anda mengumpulkan dan memeriksa informasi waktu di seluruh perangkat Android, sehingga Anda dapat mengetahui ketika masalah performa tata letak menyebabkan masalah performa. Untuk informasi selengkapnya tentang Systrace, lihat ringkasan pelacakan sistem.

Rendering GPU profil

Alat lain yang paling mungkin memberi Anda informasi konkret tentang bottleneck performa adalah fitur Rendering GPU profil di perangkat, yang tersedia di perangkat yang didukung oleh Android 6.0 (API level 23) dan yang lebih baru. Alat ini memungkinkan Anda melihat berapa lama waktu yang dibutuhkan oleh tahap tata-letak-dan-pengukuran untuk setiap frame rendering. Data ini dapat membantu Anda mendiagnosis masalah performa waktu proses, dan membantu Anda menentukan sesuatu, jika ada masalah tata letak-dan-ukuran yang perlu Anda atasi.

Dalam representasi grafis data yang ditangkapnya, Rendering GPU profil menggunakan warna biru untuk menggambarkan waktu pembuatan tata letak. Untuk informasi selengkapnya tentang cara menggunakan alat ini, lihat Panduan Rendering GPU Profil.

Lint

Alat Lint Android Studio dapat membantu Anda merasakan kurangnya efisiensi dalam hierarki tampilan. Untuk menggunakan fitur ini, pilih Analyze > Inspect Code, seperti yang ditunjukkan pada Gambar 1.

Gambar 1. Menemukan Inspect Code di Android Studio.

Informasi tentang berbagai item tata letak muncul di Android > Lint > Performance. Untuk melihat detail selengkapnya, Anda dapat mengklik masing-masing item untuk memperluasnya dan melihat informasi lebih lanjut dalam panel di sebelah kanan layar. Gambar 2 menunjukkan contoh tampilan tersebut.

Gambar 2. Menampilkan informasi tentang masalah spesifik yang tidak teridentifikasi fitur lint.

Mengklik salah satu item ini akan membuka masalah yang terkait dengan item tersebut di panel sebelah kanan.

Untuk memahami topik dan masalah spesifik di bidang ini lebih lanjut, lihat dokumentasi Lint.

Layout Inspector

Alat Layout Inspector Android Studio memberikan representasi visual dari hierarki tampilan aplikasi Anda. Ini adalah cara yang baik untuk menavigasi hierarki aplikasi Anda, memberikan representasi visual yang jelas dari rantai induk tampilan tertentu, dan memungkinkan Anda memeriksa tata letak yang dibuat oleh aplikasi Anda.

Tampilan yang disajikan oleh Layout Inspector juga dapat membantu mengidentifikasi masalah performa yang timbul dari taksasi ganda. Ini juga dapat memberikan cara mudah bagi Anda untuk mengidentifikasi rantai tata letak bersarang yang mendalam, atau area tata letak dengan jumlah turunan bersarang yang banyak, dan potensi sumber biaya performa yang lain. Dalam skenario ini, tahap tata letak-dan-ukuran bisa menjadi sangat mahal, sehingga menyebabkan masalah performa.

Untuk informasi selengkapnya, lihat Men-debug tata letak Anda dengan layout inspector.

Menyelesaikan masalah hierarki tampilan

Konsep dasar di balik penyelesaian masalah performa yang muncul dari hierarki tampilan merupakan konsep yang sederhana, tetapi lebih sulit dalam praktiknya. Mencegah hierarki tampilan agar tidak menerapkan penalti performa mencakup tujuan ganda yaitu meratakan hierarki tampilan Anda dan mengurangi taksasi ganda. Bagian ini membahas beberapa strategi untuk mencapai tujuan tersebut.

Menghapus tata letak bersarang yang redundan

Developer sering menggunakan tata letak bersarang lebih dari yang diperlukan. Misalnya, container RelativeLayout mungkin berisi satu turunan yang juga berupa container RelativeLayout. Penyarangan ini menyebabkan redundansi, dan menambah biaya yang tidak perlu ke hierarki tampilan.

Lint sering kali dapat menandai masalah ini untuk Anda, sehingga akan mengurangi waktu debugging.

Mengadopsi merge/include

Salah satu penyebab seringnya terjadi tata letak bersarang yang redundan adalah tag <include>. Misalnya, Anda dapat menentukan tata letak yang bisa digunakan lagi seperti berikut:

    <LinearLayout>
        <!-- some stuff here -->
    </LinearLayout>
    

Kemudian tag include ditambahkan ke item ini pada container induk:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/app_bg"
        android:gravity="center_horizontal">

        <include layout="@layout/titlebar"/>

        <TextView android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:text="@string/hello"
                  android:padding="10dp" />

        ...

    </LinearLayout>
    

Include ini secara tidak perlu menyarangkan tata letak pertama dalam tata letak kedua.

Tag merge dapat membantu mencegah masalah ini. Untuk informasi tentang tag ini, lihat Menggunakan kembali tata letak dengan <include>.

Mengadopsi tata letak yang lebih murah

Anda mungkin tidak dapat menyesuaikan skema tata letak yang ada agar tidak berisi tata letak redundan. Dalam kasus tertentu, satu-satunya solusi mungkin adalah meratakan hierarki Anda dengan beralih ke jenis tata letak yang sama sekali berbeda.

Misalnya, Anda mungkin menemukan bahwa TableLayout menyediakan fungsi yang sama dengan tata letak yang lebih kompleks dengan banyak dependensi posisional. Dalam rilis N Android, class ConstraintLayout menyediakan fungsionalitas yang mirip dengan RelativeLayout, tetapi dengan biaya yang jauh lebih rendah.