Mengoptimalkan gambar bitmap

Penggunaan gambar dapat menimbulkan masalah performa dengan cepat jika Anda tidak berhati-hati. Bahkan grafik kecil dalam format terkompresi seperti JPG atau PNG dapat berubah menjadi bitmap besar saat didekode untuk ditampilkan. Jika tidak efisien dalam menggunakan grafis, Anda dapat mengalami masalah memori yang dapat merusak performa aplikasi Anda dan aplikasi lain di perangkat. Ikuti praktik terbaik berikut untuk memastikan aplikasi Anda berperforma terbaik.

Menggunakan library pemuatan gambar

Anda dapat meningkatkan efisiensi aplikasi dengan menggunakan library pemuatan gambar seperti Coil (untuk project yang mengutamakan Kotlin) atau Glide (untuk project Java). Library ini mengurangi penggunaan memori aplikasi Anda dengan melakukan hal-hal seperti menyimpan cache gambar, menurunkan sampel grafis jika diperlukan, dan mendaur ulang objek grafis.

Mengurangi kualitas gambar

Pastikan untuk menggunakan ukuran gambar yang sesuai dengan kebutuhan Anda. Anda harus menghindari memuat gambar beresolusi tinggi yang besar ke dalam penampung kecil (seperti thumbnail). Sebagai gantinya, gunakan downsampling untuk memperkecil skala gambar sebelum mendekodenya ke dalam memori.

Pengecilan sampel sisi klien

Library pemuatan gambar seperti Coil dan Glide menangani penurunan sampel untuk Anda secara otomatis. Anda dapat mengonfigurasi strategi pengurangan sampelnya menggunakan ImageLoader (untuk Coil) atau DownsampleStrategy (untuk Glide). Jika mengelola bitmap secara manual, Anda dapat menggunakan inSampleSize untuk mendekode versi yang lebih kecil. Untuk melakukannya dengan aman, Anda harus menetapkan inJustDecodeBounds ke true terlebih dahulu untuk membaca dimensi gambar tanpa mengalokasikan memori, menghitung ukuran sampel, menetapkan inSampleSize ke nilai tersebut, menetapkan inJustDecodeBounds ke false, lalu mendekode gambar.

Lebih memilih pengubahan ukuran sisi server

Jika memungkinkan, minta dimensi gambar persis yang Anda butuhkan langsung dari server backend Anda. Hal ini akan mengurangi penggunaan jaringan dan jejak cache disk Anda, sekaligus memberikan penggunaan memori yang lebih ringan dengan menghindari overhead memori saat mengubah ukuran gambar di perangkat.

Anda dapat mengonfigurasi library untuk menambahkan ukuran tampilan target secara dinamis ke URL gambar. Misalnya, Coil mengizinkan hal ini menggunakan pencegat kustom, dan Glide mendukungnya menggunakan pemuat model kustom (seperti BaseGlideUrlLoader).

Menghindari ukuran tata letak yang tidak dibatasi

Agar pemuat gambar dapat melakukan downsampling (sisi klien atau sisi server) secara efektif, pemuat gambar harus mengetahui ukuran target sebelum menjalankan permintaan.

Hindari penggunaan wrapContentSize atau membiarkan dimensi tidak dibatasi pada composable yang memuat gambar jarak jauh. Jika library ini tidak dapat menyimpulkan batas target, library akan kembali memuat gambar berukuran penuh asli. Hal ini dapat menyebabkan pemuatan gambar yang jauh lebih besar daripada yang diperlukan, sehingga meningkatkan penggunaan memori dan latensi.

Sebagai gantinya, tetapkan dimensi eksplisit pada composable gambar Anda (misalnya, menggunakan Modifier.size) atau tentukan rasio aspek. Hal ini memungkinkan mesin tata letak untuk menghitung target piksel yang tepat di awal, yang kemudian dapat digunakan oleh pemuat gambar untuk meminta dan mendekode aset berukuran tepat.

Menyediakan resource alternatif untuk berbagai ukuran layar

Jika Anda mengirimkan gambar dengan aplikasi, sebaiknya sediakan aset dengan ukuran yang berbeda untuk resolusi perangkat yang berbeda. Hal ini dapat membantu mengurangi ukuran download aplikasi Anda di perangkat, dan meningkatkan performa karena aplikasi tersebut akan memuat gambar beresolusi lebih rendah di perangkat beresolusi lebih rendah. Untuk informasi selengkapnya tentang cara menyediakan bitmap alternatif untuk berbagai ukuran perangkat, lihat dokumentasi bitmap alternatif.

Jangan menerapkan padding secara langsung

Terkadang Anda mungkin perlu menambahkan padding ke gambar. Misalnya, Anda mungkin ingin gambar dikelilingi oleh batas transparan untuk letterboxing. Dalam situasi tersebut, jangan tambahkan padding langsung ke gambar, karena akan mengubah dimensi gambar. Sebagai gantinya, biarkan dimensi gambar apa adanya, dan sesuaikan lokasi gambar di layar menggunakan InsetDrawable. Atau, Anda dapat menambahkan padding ke Composable atau View yang memuat gambar.

Memilih format piksel yang tepat

Seimbangkan memori dan kualitas dengan memilih format piksel yang tepat. Gunakan RGB_565 jika Anda tidak memerlukan transparansi; format ini menggunakan setengah memori dari format ARGB_8888 default.

Di Glide, Anda dapat mengonfigurasi ini menggunakan DecodeFormat. Di Coil, Anda dapat menggunakan properti bitmapConfig.

Gunakan vektor jika memungkinkan

Untuk gambar yang terdiri dari bentuk geometris, grafik vektor jauh lebih kecil daripada bitmap dan dapat diskalakan dengan lancar untuk kepadatan tampilan apa pun. Jika sesuai, gunakan elemen seperti ShapeDrawable untuk merepresentasikan grafik.

Lepaskan dan gunakan kembali bitmap jika memungkinkan

File grafis besar dapat menggunakan banyak memori. Untuk mengurangi dampaknya, Anda harus melepaskan atau menggunakan kembali objek grafis kapan pun Anda bisa.

Jika Anda menggunakan library pemuatan gambar, pastikan untuk melepaskan bitmap ke kumpulan yang dikelola library saat Anda tidak lagi membutuhkannya. Library dapat menggunakan kembali objek jika diperlukan, dan menyediakan buffer memori untuk kebutuhan mendatang.

Jika mengelola grafis secara manual, Anda harus melepaskan bitmap setelah selesai menggunakannya dengan memanggil Bitmap.recycle dan segera menghapus referensi Bitmap, bukan mengandalkan pembersihan sampah memori.

Tips dan trik lainnya

Bagian ini mencantumkan beberapa cara lain untuk meningkatkan performa aplikasi Anda saat menangani grafis.

Jangan mengemas gambar besar dengan file AAB/APK Anda

Salah satu penyebab utama ukuran download aplikasi yang besar adalah grafik yang dikemas dalam file AAB atau APK. Gunakan alat APK Analyzer untuk memastikan Anda tidak mengemas file gambar yang lebih besar dari yang diperlukan. Kurangi ukuran atau sebaiknya tempatkan gambar di server dan hanya download saat diperlukan.

Menemukan bitmap yang redundan

Jika Anda memiliki beberapa salinan gambar yang sama, hal itu akan memboroskan memori. Anda dapat menggunakan profiler Android Studio untuk mengidentifikasi grafis yang berlebihan. Gunakan penganalisis heap dump untuk merekam heap dump, dan memfilter hasil dengan memilih setelan bitmap duplikat.

Saat menggunakan ImageBitmap, panggil prepareToDraw sebelum menggambar

Saat menggunakan ImageBitmap, untuk memulai proses upload tekstur ke GPU, panggil ImageBitmap#prepareToDraw() sebelum benar-benar menggambarnya. Tindakan ini membantu GPU menyiapkan tekstur dan meningkatkan performa tampilan visual di layar. Sebagian besar library pemuatan gambar sudah melakukan pengoptimalan ini, tetapi jika Anda menangani class ImageBitmap sendiri, Anda harus mempertimbangkannya.

Sebaiknya teruskan Int DrawableRes atau URL sebagai parameter ke composable, bukan Painter

Karena rumitnya menangani gambar (misalnya, menulis fungsi yang setara untuk Bitmaps akan sangat mahal dari segi komputasi), Painter API secara eksplisit tidak ditandai sebagai stabil dengan anotasi @Stable. Class yang tidak stabil dapat menyebabkan rekomposisi yang tidak perlu karena compiler tidak dapat melakukan inferensi dengan mudah jika data telah berubah.

Oleh karena itu, sebaiknya teruskan URL atau ID resource drawable sebagai parameter ke composable Anda, bukan meneruskan Painter sebagai parameter.

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}