Saya mengembangkan aplikasi yang menggunakan banyak gambar di Android.
Aplikasi ini berjalan sekali, mengisi informasi pada layar ( Layouts
, Listviews
, Textviews
, ImageViews
, dll) dan user membaca informasi.
Tidak ada animasi, tidak ada efek khusus atau apa pun yang dapat mengisi memori. Terkadang drawable dapat berubah. Beberapa sumber daya android dan beberapa file disimpan dalam folder di SDCARD.
Kemudian pengguna berhenti ( onDestroy
metode ini dieksekusi dan aplikasi tetap berada di memori oleh VM) dan kemudian di beberapa titik pengguna memasukkan lagi.
Setiap kali pengguna masuk ke aplikasi, saya bisa melihat memori semakin bertambah sampai pengguna mendapatkan java.lang.OutOfMemoryError
.
Jadi apa cara terbaik / yang benar untuk menangani banyak gambar?
Haruskah saya menempatkan mereka dalam metode statis sehingga tidak dimuat sepanjang waktu? Apakah saya harus membersihkan tata letak atau gambar yang digunakan dalam tata letak dengan cara khusus?
sumber
Jawaban:
Sepertinya Anda memiliki kebocoran memori. Masalahnya tidak menangani banyak gambar, itu adalah bahwa gambar Anda tidak mendapatkan alokasi saat aktivitas Anda dihancurkan.
Sulit untuk mengatakan mengapa ini tanpa melihat kode Anda. Namun, artikel ini memiliki beberapa kiat yang mungkin membantu:
http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html
Secara khusus, menggunakan variabel statis cenderung membuat segalanya lebih buruk, bukan lebih baik. Anda mungkin perlu menambahkan kode yang menghapus panggilan balik ketika aplikasi Anda digambar ulang - tetapi sekali lagi, tidak ada cukup informasi di sini untuk mengatakan dengan pasti.
sumber
Salah satu kesalahan paling umum yang saya temukan dalam mengembangkan Aplikasi Android adalah kesalahan "java.lang.OutOfMemoryError: Bitmap Size Exceed VM Budget". Saya menemukan kesalahan ini sering pada kegiatan menggunakan banyak bitmap setelah mengubah orientasi: Kegiatan dihancurkan, dibuat lagi dan tata letak "meningkat" dari XML memakan memori VM yang tersedia untuk bitmap.
Bitmap pada tata letak aktivitas sebelumnya tidak dialokasikan dengan benar oleh pengumpul sampah karena mereka telah melewati referensi ke aktivitas mereka. Setelah banyak percobaan saya menemukan solusi yang cukup bagus untuk masalah ini.
Pertama, atur atribut "id" pada tampilan induk dari tata letak XML Anda:
Kemudian, pada
onDestroy()
metode Aktivitas Anda, panggilunbindDrawables()
metode yang meneruskan referensi ke Tampilan induk dan kemudian lakukan aSystem.gc()
.unbindDrawables()
Metode ini mengeksplorasi pohon tampilan secara rekursif dan:sumber
Untuk menghindari masalah ini Anda dapat menggunakan metode asli
Bitmap.recycle()
sebelumnull
-ingBitmap
objek (atau pengaturan nilai lain). Contoh:Dan selanjutnya Anda dapat mengubah tanpa
myBitmap
panggilanSystem.gc()
seperti:sumber
Saya telah mengalami masalah yang tepat ini. Tumpukannya cukup kecil sehingga gambar-gambar ini bisa lepas kendali agak cepat dalam hal memori. Salah satu caranya adalah memberi pengumpul sampah petunjuk untuk mengumpulkan memori pada bitmap dengan memanggil metode daur ulangnya .
Juga, metode onDestroy tidak dijamin untuk dipanggil. Anda mungkin ingin memindahkan logika ini / membersihkan ke aktivitas onPause. Lihatlah diagram / tabel Siklus Hidup Aktivitas di halaman ini untuk informasi lebih lanjut.
sumber
onPause
sarannya. Saya menggunakan 4 tab denganBitmap
gambar di dalamnya semua, jadi menghancurkan aktivitas mungkin tidak terjadi terlalu cepat (jika pengguna menelusuri semua tab).Penjelasan ini mungkin membantu: http://code.google.com/p/android/issues/detail?id=8488#c80
"Kiat Cepat:
1) PERNAH panggil System.gc () sendiri. Ini telah disebarkan sebagai perbaikan di sini, dan itu tidak berhasil. Jangan lakukan itu. Jika Anda perhatikan dalam penjelasan saya, sebelum mendapatkan OutOfMemoryError, JVM sudah menjalankan pengumpulan sampah sehingga tidak ada alasan untuk melakukannya lagi (ini memperlambat program Anda). Melakukan satu di akhir aktivitas Anda hanya menutupi masalahnya. Ini dapat menyebabkan bitmap ditempatkan pada antrian finalizer lebih cepat, tetapi tidak ada alasan Anda tidak bisa hanya memanggil daur ulang pada setiap bitmap saja.
2) Selalu panggil daur ulang () pada bitmap yang tidak Anda perlukan lagi. Paling tidak, di onDestroy aktivitas Anda, lewati dan daur ulang semua bitmap yang Anda gunakan. Juga, jika Anda ingin instance bitmap dikumpulkan dari tumpukan dalvik lebih cepat, tidak ada salahnya untuk menghapus referensi apa pun ke bitmap.
3) Memanggil daur ulang () dan kemudian System.gc () masih mungkin tidak menghapus bitmap dari tumpukan Dalvik. JANGAN PERNAH khawatir tentang hal ini. recycle () melakukan tugasnya dan membebaskan memori asli, itu hanya akan mengambil beberapa waktu untuk melalui langkah-langkah yang saya uraikan sebelumnya untuk benar-benar menghapus bitmap dari tumpukan Dalvik. Ini BUKAN masalah besar karena sebagian besar memori asli sudah gratis!
4) Selalu menganggap ada bug dalam kerangka terakhir. Dalvik melakukan apa yang seharusnya dilakukan. Mungkin bukan apa yang Anda harapkan atau apa yang Anda inginkan, tetapi cara kerjanya. "
sumber
Saya memiliki masalah yang sama persis. Setelah beberapa pengujian saya menemukan bahwa kesalahan ini muncul untuk penskalaan gambar besar. Saya mengurangi skala gambar dan masalahnya hilang.
PS Awalnya saya mencoba mengurangi ukuran gambar tanpa menurunkan gambar. Itu tidak menghentikan kesalahan.
sumber
Poin-poin berikut sangat membantu saya. Mungkin ada poin lain juga, tetapi ini sangat penting:
sumber
Saya menyarankan cara yang mudah untuk menyelesaikan masalah ini. Cukup berikan nilai atribut "android: configChanges" seperti yang diikuti di Mainfest.xml untuk aktivitas Anda yang salah. seperti ini:
solusi pertama yang saya berikan benar-benar mengurangi frekuensi kesalahan OOM ke level yang rendah. Tapi, itu tidak menyelesaikan masalah sama sekali. Dan kemudian saya akan memberikan solusi ke-2:
Sebagai rincian OOM, saya telah menggunakan memori runtime terlalu banyak. Jadi, saya mengurangi ukuran gambar di ~ / res / drawable proyek saya. Seperti gambar yang terlalu berkualitas yang memiliki resolusi 128X128, bisa diubah ukurannya menjadi 64x64 yang juga cocok untuk aplikasi saya. Dan setelah saya melakukannya dengan tumpukan gambar, kesalahan OOM tidak terjadi lagi.
sumber
Saya juga frustrasi dengan bug memori. Dan ya, saya juga menemukan bahwa kesalahan ini banyak muncul saat menskala gambar. Awalnya saya mencoba membuat ukuran gambar untuk semua kepadatan, tetapi saya menemukan ini secara substansial meningkatkan ukuran aplikasi saya. Jadi saya sekarang hanya menggunakan satu gambar untuk semua kepadatan dan meningkatkan skala gambar saya.
Aplikasi saya akan melempar kesalahan memori luar setiap kali pengguna berpindah dari satu aktivitas ke aktivitas lainnya. Mengatur drawables saya ke null dan memanggil System.gc () tidak berfungsi, begitu pula daur ulang bitmapDrawables saya dengan getBitMap (). Recycle (). Android akan terus membuang kesalahan memori dengan pendekatan pertama, dan itu akan melempar pesan kesalahan kanvas setiap kali mencoba menggunakan bitmap daur ulang dengan pendekatan kedua.
Saya mengambil pendekatan yang ketiga. Saya mengatur semua tampilan ke nol dan latar belakang menjadi hitam. Saya melakukan pembersihan ini pada metode onStop () saya. Ini adalah metode yang dipanggil segera setelah aktivitas tidak lagi terlihat. Jika Anda melakukannya dalam metode onPause (), pengguna akan melihat latar belakang hitam. Tidak ideal Adapun melakukannya dalam metode onDestroy (), tidak ada jaminan bahwa itu akan dipanggil.
Untuk mencegah layar hitam terjadi jika pengguna menekan tombol kembali pada perangkat, saya memuat kembali aktivitas dalam metode onRestart () dengan memanggil metode startActivity (getIntent ()) dan kemudian menyelesaikan ().
Catatan: tidak perlu mengubah latar belakang menjadi hitam.
sumber
Metode * BitmapFactory.decode, dibahas dalam pelajaran Memuat Bitmap Besar Secara efisien , tidak boleh dieksekusi pada utas UI utama jika data sumber dibaca dari disk atau lokasi jaringan (atau benar-benar sumber selain memori). Waktu yang diperlukan untuk memuat data ini tidak dapat diprediksi dan tergantung pada berbagai faktor (kecepatan membaca dari disk atau jaringan, ukuran gambar, kekuatan CPU, dll.). Jika salah satu dari tugas ini memblokir utas UI, sistem menandai aplikasi Anda sebagai tidak responsif dan pengguna memiliki opsi untuk menutupnya (lihat Merancang untuk Responsif untuk informasi lebih lanjut).
sumber
Yah saya sudah mencoba semua yang saya temukan di internet dan tidak ada yang bekerja. Calling System.gc () hanya menurunkan kecepatan aplikasi. Mendaur ulang bitmap di onDestroy juga tidak berhasil untuk saya.
Satu-satunya hal yang berfungsi sekarang adalah memiliki daftar statis semua bitmap sehingga bitmap bertahan setelah restart. Dan cukup gunakan bitmap yang disimpan daripada membuat yang baru setiap kali aktivitas jika dimulai kembali.
Dalam kasus saya, kode ini terlihat seperti ini:
sumber
Saya memiliki masalah yang sama hanya dengan mengganti gambar latar belakang dengan ukuran yang masuk akal. Saya mendapat hasil yang lebih baik dengan mengatur ImageView ke nol sebelum memasukkan gambar baru.
sumber
FWIW, inilah bitmap-cache ringan yang saya kodekan dan telah digunakan selama beberapa bulan. Ini bukan all-the-bells-and-whistles, jadi baca kodenya sebelum Anda menggunakannya.
sumber