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 Anda tidak efisien dalam menggunakan grafik, Anda dapat mengalami masalah memori yang dapat mengganggu 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 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 gambar dalam cache, menurunkan sampel grafis saat diperlukan, dan mendaur ulang objek grafis.

Melakukan downsample gambar

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

Downsampling sisi klien

Library pemuatan gambar seperti Coil dan Glide menangani penurunan sampel untuk Anda secara otomatis. Anda dapat mengonfigurasi strategi downsampling-nya menggunakan ImageLoader (untuk Coil) atau DownsampleStrategy (untuk Glide). Jika Anda mengelola bitmap secara manual, Anda dapat menggunakan inSampleSize untuk mendekode versi yang lebih kecil. Untuk melakukannya dengan aman, Anda harus terlebih dahulu menetapkan inJustDecodeBounds ke true 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 yang Anda perlukan langsung dari server backend. Hal ini 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 interceptor kustom, dan Glide mendukungnya menggunakan loader model kustom (seperti BaseGlideUrlLoader).

Menghindari ukuran tata letak yang tidak dibatasi

Agar loader gambar dapat melakukan downsample (sisi klien atau sisi server) secara efektif, loader 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 tersebut akan kembali memuat gambar ukuran penuh yang asli. Hal ini dapat menyebabkan pemuatan gambar yang jauh lebih besar dari 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 dengan ukuran yang benar.

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 menambahkan padding langsung ke gambar, sehingga 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 menyimpan 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 mengonfigurasinya menggunakan DecodeFormat. Di Coil, Anda dapat menggunakan properti bitmapConfig.

Menggunakan vektor jika memungkinkan

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

Melepaskan dan menggunakan kembali bitmap jika memungkinkan

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

Jika Anda menggunakan library pemuatan gambar, pastikan untuk merilis bitmap ke kumpulan terkelola library saat Anda tidak lagi membutuhkannya. Library dapat menggunakan kembali objek saat diperlukan, dan menjaga buffer memori tetap tersedia untuk kebutuhan mendatang.

Jika Anda mengelola grafik secara manual, Anda harus merilis 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

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 redundan

Jika Anda memiliki beberapa salinan gambar yang sama, hal itu akan memboroskan memori. Anda dapat menggunakan profiler Android Studio untuk mengidentifikasi grafik yang redundan. Gunakan penganalisis heap dump untuk mengambil heap dump, dan filter hasilnya 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.

Memilih meneruskan 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) {

}