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 memengaruhi 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 meng-cache gambar, melakukan downsampling grafik jika diperlukan, dan mendaur ulang objek grafik.

Melakukan downsampling gambar

Pastikan Anda 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.

Downsampling sisi klien

Library pemuatan gambar seperti Coil dan Glide menangani downsampling untuk Anda secara otomatis. Anda dapat mengonfigurasi strategi downsampling-nya 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.

Memilih pengubahan ukuran sisi server

Jika memungkinkan, minta dimensi gambar yang tepat yang Anda butuhkan langsung dari server backend. 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 interseptor 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 ukuran penuh 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 menghitung target piksel yang tepat di awal, yang kemudian dapat digunakan oleh pemuat gambar untuk meminta dan mendekode aset berukuran 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 tambahkan padding langsung ke gambar, yang akan mengubah dimensi gambar. Sebagai gantinya, biarkan dimensi gambar seperti apa adanya, dan sesuaikan lokasi gambar di layar menggunakan InsetDrawable. Atau, Anda dapat menambahkan padding ke dalam Composable atau Tampilan yang berisi 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 hal ini menggunakan DecodeFormat. Di Coil, Anda dapat menggunakan properti bitmapConfig.

Menggunakan 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.

Merilis dan menggunakan kembali bitmap jika memungkinkan

File grafik besar dapat menggunakan banyak memori. Untuk mengurangi dampaknya, Anda harus merilis atau menggunakan kembali objek grafik jika memungkinkan.

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

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

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 yang berlebihan

Jika Anda memiliki beberapa salinan gambar yang sama, hal itu akan membuang memori. Anda dapat menggunakan profiler Android Studio untuk mengidentifikasi grafik yang berlebihan. Gunakan heap dump analyzer untuk merekam heap dump, dan memfilter hasilnya dengan memilih setelan duplicate bitmaps.

Memanggil prepareToDraw sebelum menggambar, saat menggunakan ImageBitmap

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 @Stable anotasi. 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) {

}