Saya memiliki tampilan daftar dengan beberapa tombol gambar di setiap baris. Ketika Anda mengklik baris daftar, itu meluncurkan aktivitas baru. Saya harus membuat tab sendiri karena ada masalah dengan tata letak kamera. Aktivitas yang diluncurkan untuk hasilnya adalah peta. Jika saya mengklik tombol saya untuk meluncurkan pratinjau gambar (memuat gambar dari kartu SD) aplikasi kembali dari aktivitas kembali ke listview
aktivitas ke pengendali hasil untuk meluncurkan kembali aktivitas baru saya yang tidak lebih dari widget gambar.
Pratinjau gambar pada tampilan daftar sedang dilakukan dengan kursor dan ListAdapter
. Ini membuatnya cukup sederhana, tetapi saya tidak yakin bagaimana saya dapat menempatkan ukuran gambar (Yaitu ukuran bit lebih kecil bukan pixel sebagai src
untuk tombol gambar on the fly. Jadi saya hanya mengubah ukuran gambar yang keluar dari kamera ponsel.
Masalahnya adalah saya mendapatkan kesalahan memori saat mencoba kembali dan meluncurkan kembali aktivitas ke-2.
- Apakah ada cara saya bisa membuat daftar adaptor dengan mudah baris demi baris, di mana saya dapat mengubah ukuran dengan cepat ( sedikit bijak )?
Ini akan lebih baik karena saya juga perlu membuat beberapa perubahan pada properti widget / elemen di setiap baris karena saya tidak dapat memilih baris dengan layar sentuh karena masalah fokus. ( Saya bisa menggunakan roller ball. )
- Saya tahu saya bisa melakukan perubahan ukuran band dan menyimpan gambar saya, tapi itu bukan yang ingin saya lakukan, tetapi beberapa kode contoh untuk itu akan menyenangkan.
Segera setelah saya menonaktifkan gambar pada tampilan daftar itu berfungsi dengan baik lagi.
FYI: Ini adalah bagaimana saya melakukannya:
String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME + ""};
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
Dimana R.id.imagefilename
a ButtonImage
.
Ini LogCat saya:
01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed
Saya juga memiliki kesalahan baru saat menampilkan gambar:
01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri:
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed
sumber
Jawaban:
Kelas Pelatihan Android , " Menampilkan Bitmap dengan Efisien ", menawarkan beberapa informasi hebat untuk memahami dan menangani pengecualian
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
saat memuat Bitmap.Baca Dimensi dan Jenis Bitmap
The
BitmapFactory
kelas menyediakan beberapa metode decoding (decodeByteArray()
,decodeFile()
,decodeResource()
, dll) untuk menciptakanBitmap
dari berbagai sumber. Pilih metode decode yang paling tepat berdasarkan sumber data gambar Anda. Metode ini berupaya mengalokasikan memori untuk bitmap yang dibangun dan karenanya dapat dengan mudah menghasilkanOutOfMemory
pengecualian. Setiap jenis metode decode memiliki tanda tangan tambahan yang memungkinkan Anda menentukan opsi decoding melaluiBitmapFactory.Options
kelas. MengaturinJustDecodeBounds
properti ketrue
saat decoding menghindari alokasi memori, kembalinull
ke objek bitmap tetapi pengaturanoutWidth
,outHeight
danoutMimeType
. Teknik ini memungkinkan Anda untuk membaca dimensi dan tipe data gambar sebelum konstruksi (dan alokasi memori) dari bitmap.Untuk menghindari
java.lang.OutOfMemory
pengecualian, periksa dimensi bitmap sebelum mendekodekannya, kecuali jika Anda benar-benar memercayai sumber untuk memberi Anda data gambar berukuran yang dapat diprediksi yang sesuai dengan memori yang tersedia.Muat versi yang diperkecil ke dalam Memori
Sekarang setelah dimensi gambar diketahui, mereka dapat digunakan untuk memutuskan apakah gambar penuh harus dimuat ke dalam memori atau jika versi subsampel harus dimuat sebagai gantinya. Berikut adalah beberapa faktor yang perlu dipertimbangkan:
Misalnya, tidak layak memuat gambar 1024x768 piksel ke dalam memori jika akhirnya akan ditampilkan dalam thumbnail 128x96 piksel dalam
ImageView
.Untuk memberitahu decoder untuk melakukan subsampel gambar, memuat versi yang lebih kecil ke dalam memori, atur
inSampleSize
ketrue
dalamBitmapFactory.Options
objek Anda . Sebagai contoh, sebuah gambar dengan resolusi 2048x1536 yang diterjemahkan dengan aninSampleSize
of 4 menghasilkan bitmap sekitar 512x384. Memuat ini ke dalam memori menggunakan 0.75MB daripada 12MB untuk gambar penuh (dengan asumsi konfigurasi bitmapARGB_8888
). Berikut adalah metode untuk menghitung nilai ukuran sampel yang merupakan kekuatan dua berdasarkan lebar dan tinggi target:Untuk menggunakan metode ini, pertama decode dengan
inJustDecodeBounds
set totrue
, melewati opsi melalui dan kemudian decode lagi menggunakan nilai baruinSampleSize
daninJustDecodeBounds
set kefalse
:Metode ini membuatnya mudah untuk memuat bitmap ukuran besar secara sewenang-wenang ke dalam
ImageView
yang menampilkan thumbnail 100x100 piksel, seperti yang ditunjukkan dalam kode contoh berikut:Anda dapat mengikuti proses serupa untuk memecahkan kode bitmap dari sumber lain, dengan mengganti
BitmapFactory.decode*
metode yang sesuai sesuai kebutuhan.sumber
Untuk memperbaiki kesalahan OutOfMemory, Anda harus melakukan sesuatu seperti ini:
inSampleSize
Opsi ini mengurangi konsumsi memori.Inilah metode yang lengkap. Pertama membaca ukuran gambar tanpa men-decoding konten itu sendiri. Kemudian ia menemukan nilai terbaik
inSampleSize
, itu harus kekuatan 2, dan akhirnya gambar diterjemahkan.sumber
Saya telah membuat sedikit perbaikan pada kode Fedor. Ini pada dasarnya melakukan hal yang sama, tetapi tanpa (menurut saya) jelek saat loop dan selalu menghasilkan kekuatan dua. Kudos to Fedor untuk membuat solusi asli, saya terjebak sampai saya menemukannya, dan kemudian saya bisa membuat yang ini :)
sumber
BitmapFactory.decodeStream()
. Tidakkah Anda harus menyimpan referensi untuk masing-masing sehingga mereka dapat ditutup difinally
blok?Saya berasal dari pengalaman iOS dan saya frustrasi menemukan masalah dengan sesuatu yang sangat mendasar seperti memuat dan menampilkan gambar. Lagi pula, semua orang yang mengalami masalah ini mencoba menampilkan gambar berukuran cukup. Bagaimanapun, berikut adalah dua perubahan yang memperbaiki masalah saya (dan membuat aplikasi saya sangat responsif).
1) Setiap kali Anda melakukannya
BitmapFactory.decodeXYZ()
, pastikan untuk lulusBitmapFactory.Options
denganinPurgeable
set ketrue
(dan lebih disukai denganinInputShareable
juga set ketrue
).2) JANGAN PERNAH digunakan
Bitmap.createBitmap(width, height, Config.ARGB_8888)
. Maksud saya TIDAK PERNAH! Saya tidak pernah mengalami hal yang tidak meningkatkan kesalahan memori setelah melewati beberapa. Tidak ada jumlahrecycle()
,System.gc()
, apa pun membantu. Itu selalu menimbulkan pengecualian. Salah satu cara lain yang benar-benar berfungsi adalah memiliki gambar dummy di drawables Anda (atau Bitmap lain yang Anda dekodekan menggunakan langkah 1 di atas), skala ulang ke apa pun yang Anda inginkan, kemudian memanipulasi Bitmap yang dihasilkan (seperti meneruskannya ke Kanvas untuk lebih banyak kesenangan). Jadi, apa yang harus Anda gunakan sebagai gantinya adalah:Bitmap.createScaledBitmap(srcBitmap, width, height, false)
. Jika karena alasan apa pun Anda HARUS menggunakan metode brute force create, maka setidaknya lulusConfig.ARGB_4444
.Ini hampir dijamin untuk menghemat waktu Anda jika bukan berhari-hari. Semua yang berbicara tentang penskalaan gambar, dll. Tidak benar-benar berfungsi (kecuali jika Anda menganggap ukuran yang salah atau gambar yang terdegradasi sebagai solusi).
sumber
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true;
danBitmap.createScaledBitmap(srcBitmap, width, height, false);
memecahkan masalah saya dengan pengecualian memori di Android 4.0.0. Terima kasih sobat!BitmapFactory.Options.inPurgeable
danBitmapFactory.Options.inInputShareable
sudah ditinggalkan developer.android.com/reference/android/graphics/…Ini adalah bug yang dikenal , bukan karena file besar. Karena Android Cache Drawables, itu kehabisan memori setelah menggunakan beberapa gambar. Tapi saya telah menemukan cara alternatif untuk itu, dengan melewatkan sistem cache default android.
Solusi : Pindahkan gambar ke folder "aset" dan gunakan fungsi berikut untuk mendapatkan BitmapDrawable:
sumber
Saya memiliki masalah yang sama dan menyelesaikannya dengan menghindari fungsi BitmapFactory.decodeStream atau decodeFile dan sebagai gantinya digunakan
BitmapFactory.decodeFileDescriptor
decodeFileDescriptor
sepertinya memanggil metode asli yang berbeda dari decodeStream / decodeFile.Ngomong - ngomong , apa yang berhasil adalah ini (perhatikan bahwa saya menambahkan beberapa opsi seperti beberapa di atas, tetapi bukan itu yang membuat perbedaan. Yang penting adalah panggilan ke BitmapFactory.decodeFileDescriptor alih-alih decodeStream atau decodeFile ):
Saya pikir ada masalah dengan fungsi asli yang digunakan di decodeStream / decodeFile. Saya telah mengkonfirmasi bahwa metode asli yang berbeda dipanggil saat menggunakan decodeFileDescriptor. Juga yang saya baca adalah "bahwa Gambar (Bitmap) tidak dialokasikan dalam cara Java standar tetapi melalui panggilan asli; alokasi dilakukan di luar tumpukan virtual, tetapi dihitung menentangnya! "
sumber
Saya pikir cara terbaik untuk menghindari
OutOfMemoryError
adalah dengan menghadapinya dan memahaminya.Saya membuat aplikasi untuk sengaja menyebabkan
OutOfMemoryError
, dan memonitor penggunaan memori.Setelah saya melakukan banyak percobaan dengan Aplikasi ini, saya mendapat kesimpulan berikut:
Saya akan berbicara tentang versi SDK sebelum Honey Comb dulu.
Bitmap disimpan di heap asli, tetapi itu akan mengumpulkan sampah secara otomatis, panggilan daur ulang () tidak perlu.
Jika {VM heap size} + {memory heap native dialokasikan}> = {VM heap size limit untuk perangkat}, dan Anda mencoba membuat bitmap, OOM akan dilempar.
PEMBERITAHUAN: VM HEAP SIZE lebih dihitung daripada MEMORY ALLOCATED VM.
Ukuran VM Heap tidak akan pernah menyusut setelah tumbuh, bahkan jika memori VM yang dialokasikan menyusut.
Jadi Anda harus menjaga memori VM puncak serendah mungkin untuk menjaga VM Heap Size tidak tumbuh terlalu besar untuk menghemat memori yang tersedia untuk Bitmap.
Secara manual memanggil System.gc () tidak ada artinya, sistem akan memanggilnya terlebih dahulu sebelum mencoba menumbuhkan ukuran tumpukan.
Native Heap Size tidak akan menyusut juga, tetapi tidak dihitung untuk OOM, jadi tidak perlu khawatir.
Lalu, mari kita bicara tentang Mulai SDK dari Honey Comb.
Bitmap disimpan dalam tumpukan VM, Memori asli tidak dihitung untuk OOM.
Kondisi untuk OOM jauh lebih sederhana: {VM heap size}> = {VM heap size limit untuk perangkat}.
Jadi Anda memiliki lebih banyak memori yang tersedia untuk membuat bitmap dengan batas ukuran tumpukan yang sama, OOM lebih kecil kemungkinannya untuk dibuang.
Berikut adalah beberapa pengamatan saya tentang Pengumpulan Sampah dan Kebocoran Memori.
Anda dapat melihatnya sendiri di App. Jika suatu Kegiatan mengeksekusi AsyncTask yang masih berjalan setelah Kegiatan dihancurkan, Kegiatan tersebut tidak akan mengumpulkan sampah sampai AsyncTask selesai.
Ini karena AsyncTask adalah turunan dari kelas dalam anonim, yang memegang referensi Kegiatan.
Memanggil AsyncTask.cancel (true) tidak akan menghentikan eksekusi jika tugas diblokir dalam operasi IO di utas latar belakang.
Callback juga merupakan kelas dalam anonim, jadi jika instance statis dalam proyek Anda menahannya dan tidak melepaskannya, memori akan bocor.
Jika Anda menjadwalkan tugas yang berulang atau tertunda, misalnya Timer, dan Anda tidak memanggil cancel () dan purge () di onPause (), memori akan bocor.
sumber
private static class
di kelas yang sama. Mereka tidak akan memegang referensi apa pun untuk Kegiatan (kecuali jika Anda memberi mereka satu saja)Saya telah melihat banyak pertanyaan tentang pengecualian OOM dan caching belakangan ini. Panduan pengembang memiliki artikel yang sangat bagus tentang ini, tetapi beberapa cenderung gagal dalam mengimplementasikannya dengan cara yang sesuai.
Karena itu saya menulis contoh aplikasi yang menunjukkan caching di lingkungan Android. Implementasi ini belum mendapatkan OOM.
Lihatlah di akhir jawaban ini untuk tautan ke kode sumber.
Persyaratan:
Fitur:
ListView
jauh, itu hanya tidak akan men-download bitmap antaraIni tidak termasuk:
Kode sampel:
Gambar yang sedang diunduh adalah gambar (75x75) dari Flickr. Namun, letakkan url gambar apa pun yang Anda ingin diproses, dan aplikasi akan menurunkannya jika melebihi maksimum. Dalam aplikasi ini url-nya cukup dalam
String
array.The
LruCache
memiliki cara yang baik untuk menangani bitmap. Namun, dalam aplikasi ini saya meletakkan instanceLruCache
di dalam kelas cache lain yang saya buat untuk mendapatkan aplikasi yang lebih layak.Hal-hal penting Cache.java (
loadBitmap()
metode ini yang paling penting):Anda seharusnya tidak perlu mengedit apa pun di file Cache.java kecuali Anda ingin mengimplementasikan cache caching.
Hal-hal penting MainActivity.java:
getView()
dipanggil sangat sering. Biasanya bukan ide yang baik untuk mengunduh gambar di sana jika kami belum menerapkan pemeriksaan yang memastikan bahwa kami tidak akan memulai jumlah utas per baris yang tidak terbatas. Cache.java memeriksa apakahrowObject.mBitmapUrl
sudah ada dalam tugas dan jika sudah, itu tidak akan memulai yang lain. Oleh karena itu, kemungkinan besar kami tidak melebihi batasan antrian kerja dariAsyncTask
kumpulan.Unduh:
Anda dapat mengunduh kode sumber dari https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .
Kata-kata terakhir:
Saya telah menguji ini selama beberapa minggu sekarang, saya belum mendapatkan pengecualian OOM tunggal. Saya telah menguji ini pada emulator, pada Nexus One dan pada Nexus S. Saya telah menguji url gambar yang berisi gambar yang berkualitas HD. Satu-satunya hambatan adalah bahwa dibutuhkan lebih banyak waktu untuk mengunduh.
Hanya ada satu skenario yang mungkin di mana saya bisa membayangkan bahwa OOM akan muncul, dan itu adalah jika kita mengunduh banyak, gambar yang sangat besar, dan sebelum mereka diskalakan dan dimasukkan ke dalam cache, secara bersamaan akan mengambil lebih banyak memori dan menyebabkan OOM. Tapi itu bahkan bukan situasi yang ideal dan kemungkinan besar tidak akan mungkin untuk diselesaikan dengan cara yang lebih layak.
Laporkan kesalahan dalam komentar! :-)
sumber
Saya melakukan yang berikut untuk mengambil gambar dan mengubah ukurannya dengan cepat. Semoga ini membantu
sumber
Tampaknya ini adalah masalah yang berjalan sangat lama, dengan banyak penjelasan berbeda. Saya mengambil saran dari dua jawaban yang paling umum disajikan di sini, tetapi tidak satu pun dari ini menyelesaikan masalah VM saya dengan mengklaim tidak mampu membayar byte untuk melakukan bagian decoding dari proses. Setelah menggali, saya mengetahui bahwa masalah sebenarnya di sini adalah proses decoding yang diambil dari NATIVE tumpukan .
Lihat di sini: BitmapFactory OOM membuat saya gila
Itu membawa saya ke utas diskusi lain di mana saya menemukan beberapa solusi untuk masalah ini. Salah satunya adalah menelepon
System.gc();
secara manual setelah gambar Anda ditampilkan. Tapi itu benar-benar membuat aplikasi Anda menggunakan memori LEBIH, dalam upaya untuk mengurangi tumpukan asli. Solusi yang lebih baik pada rilis 2.0 (Donut) adalah dengan menggunakan opsi BitmapFactory "inPurgeable". Jadi saya hanya menambahkano2.inPurgeable=true;
setelahnyao2.inSampleSize=scale;
.Lebih lanjut tentang topik itu di sini: Apakah batas memori hanya menumpuk 6M?
Sekarang, setelah mengatakan semua ini, saya bodoh dengan Java dan Android juga. Jadi jika Anda berpikir ini adalah cara yang mengerikan untuk menyelesaikan masalah ini, Anda mungkin benar. ;-) Tetapi ini telah berhasil bagi saya, dan saya merasa tidak mungkin untuk menjalankan VM dari heap cache sekarang. Satu-satunya kelemahan yang saya dapat temukan adalah bahwa Anda membuang gambar yang diambil dalam cache. Yang berarti jika Anda kembali ke gambar itu, Anda menggambarnya kembali setiap waktu. Dalam hal bagaimana aplikasi saya bekerja, itu tidak terlalu menjadi masalah. Jarak tempuh Anda mungkin beragam.
sumber
sayangnya jika Tidak Ada Yang Di Atas berfungsi, lalu Tambahkan ini ke file Manifest Anda . Di dalam tag aplikasi
sumber
Gunakan ini
bitmap.recycle();
Ini membantu tanpa masalah kualitas gambar.sumber
Saya punya solusi yang jauh lebih efektif yang tidak perlu penskalaan apa pun. Cukup decode bitmap Anda hanya sekali dan kemudian cache itu di peta dengan namanya. Kemudian cukup ambil bitmap terhadap nama dan atur di ImageView. Tidak ada lagi yang perlu dilakukan.
Ini akan berfungsi karena data biner aktual dari bitmap yang di-decode tidak disimpan di dalam tumpukan VM dalvik. Itu disimpan secara eksternal. Jadi setiap kali Anda mendekode bitmap, ia mengalokasikan memori di luar tumpukan VM yang tidak pernah direklamasi oleh GC
Untuk membantu Anda lebih menghargai ini, bayangkan Anda telah menyimpan gambar Anda di folder yang dapat digambar. Anda cukup mendapatkan gambar dengan melakukan getResources (). GetDrwable (R.drawable.). Ini TIDAK akan men-decode gambar Anda setiap kali tetapi menggunakan kembali contoh yang sudah diterjemahkan setiap kali Anda menyebutnya. Jadi pada dasarnya itu di-cache.
Sekarang karena gambar Anda berada dalam file di suatu tempat (atau bahkan mungkin berasal dari server eksternal), itu adalah tanggung jawab ANDA untuk men-cache instance bitmap yang telah didekodekan untuk digunakan kembali di mana pun dibutuhkan.
Semoga ini membantu.
sumber
Saya telah mengatasi masalah yang sama dengan cara berikut.
sumber
Ada dua masalah di sini....
sumber
Ini berhasil untuk saya!
sumber
Tidak ada jawaban di atas yang bekerja untuk saya, tetapi saya menemukan solusi yang sangat buruk yang menyelesaikan masalah. Saya menambahkan gambar pixel 1x1 yang sangat kecil ke proyek saya sebagai sumber daya, dan memuatnya ke ImageView saya sebelum memanggil pengumpulan sampah. Saya pikir mungkin ImageView tidak merilis Bitmap, jadi GC tidak pernah mengambilnya. Ini jelek, tetapi tampaknya berfungsi untuk saat ini.
sumber
bitmap
dalam kode di atas adalah sebelumnya gambar yang sudah ditampilkan, Anda perlu recycle itu, jelas setiap referensi untuk itu, membuatimageView
lupa juga dengan menetapkan pengganti kecil,gc()
; dan setelah semua ini: muat gambar BARU Anda kebitmap
dan tampilkan,...
dalam kode di atas.Jawaban yang bagus di sini, tetapi saya ingin kelas yang sepenuhnya dapat digunakan untuk mengatasi masalah ini .. jadi saya melakukannya.
Ini adalah kelas BitmapHelper saya yang merupakan bukti OutOfMemoryError :-)
sumber
Ini bekerja untuk saya.
dan ini di C # monodroid. Anda dapat dengan mudah mengubah jalur gambar. yang penting di sini adalah opsi yang harus ditetapkan.
sumber
Ini sepertinya tempat yang tepat untuk membagikan kelas utilitas saya untuk memuat dan memproses gambar dengan komunitas, Anda dipersilakan untuk menggunakannya dan memodifikasinya secara bebas.
sumber
Di salah satu aplikasi saya, saya perlu mengambil gambar dari
Camera/Gallery
. Jika pengguna mengklik gambar dari Kamera (mungkin 2MP, 5MP atau 8MP), ukuran gambar bervariasi darikB
s keMB
s. Jika ukuran gambar kurang (atau hingga 1-2MB) di atas kode berfungsi dengan baik tetapi jika saya memiliki gambar ukuran di atas 4MB atau 5MB makaOOM
datang dalam bingkai :(maka saya telah bekerja untuk menyelesaikan masalah ini & akhirnya saya membuat perbaikan di bawah ini ke kode Fedor (Semua Kredit ke Fedor untuk membuat solusi yang bagus) :)
Saya harap ini akan membantu teman-teman yang menghadapi masalah yang sama!
untuk lebih lanjut silakan lihat ini
sumber
Saya baru saja mengalami masalah ini beberapa menit yang lalu. Saya menyelesaikannya dengan melakukan pekerjaan yang lebih baik dalam mengelola adaptor listview saya. Saya pikir itu adalah masalah dengan ratusan gambar 50x50px yang saya gunakan, ternyata saya mencoba untuk mengembang tampilan kustom saya setiap kali baris ditampilkan. Cukup dengan menguji untuk melihat apakah baris telah meningkat saya menghilangkan kesalahan ini, dan saya menggunakan ratusan bitmap. Ini sebenarnya untuk Spinner, tetapi adaptor dasar berfungsi sama untuk ListView. Perbaikan sederhana ini juga sangat meningkatkan kinerja adaptor.
sumber
Saya telah menghabiskan sepanjang hari menguji solusi ini dan satu-satunya hal yang bekerja untuk saya adalah pendekatan di atas untuk mendapatkan gambar dan secara manual memanggil GC, yang saya tahu tidak seharusnya diperlukan, tetapi itu adalah satu-satunya hal yang berhasil ketika saya meletakkan aplikasi saya di bawah pengujian beban berat, beralih di antara aktivitas. Aplikasi saya memiliki daftar gambar mini dalam tampilan daftar (katakanlah aktivitas A) dan ketika Anda mengklik salah satu gambar itu akan membawa Anda ke aktivitas lain (katakanlah aktivitas B) yang menampilkan gambar utama untuk item itu. Ketika saya akan bolak-balik antara dua aktivitas, saya akhirnya akan mendapatkan kesalahan OOM dan aplikasi akan ditutup paksa.
Ketika saya akan mendapatkan setengah jalan dari listview itu akan crash.
Sekarang ketika saya menerapkan hal berikut dalam aktivitas B, saya bisa melalui seluruh tampilan daftar tanpa masalah dan terus berjalan dan pergi dan pergi ... dan banyak yang cepat.
sumber
Masalah ini hanya terjadi pada emulator Android. Saya juga menghadapi masalah ini dalam sebuah emulator tetapi ketika saya memeriksa sebuah perangkat maka itu berfungsi dengan baik.
Jadi silakan periksa di perangkat. Ini dapat dijalankan di perangkat.
sumber
2 sen saya: saya memecahkan kesalahan OOM saya dengan bitmap dengan:
a) menskalakan gambar saya dengan faktor 2
b) menggunakan pustaka Picasso di Adaptor kustom saya untuk ListView, dengan satu panggilan di getView seperti ini:
Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);
sumber
gunakan kode ini untuk setiap gambar di pilih dari SdCard atau drewable untuk mengkonversi objek bitmap.
gunakan instend jalur gambar Anda dari ImageData_Path.get (img_pos) .getPath () .
sumber
Umumnya ukuran tumpukan perangkat android hanya 16MB (bervariasi dari perangkat / OS lihat ukuran Heap posting ), jika Anda memuat gambar dan melintasi ukuran 16MB, itu akan membuang memori keluar, daripada menggunakan Bitmap untuk, memuat gambar dari kartu SD atau dari sumber daya atau bahkan dari jaringan mencoba menggunakan getImageUri , memuat bitmap memerlukan lebih banyak memori, atau Anda dapat mengatur bitmap ke null jika pekerjaan Anda dilakukan dengan bitmap itu.
sumber
Semua solusi di sini memerlukan pengaturan IMAGE_MAX_SIZE. Ini membatasi perangkat dengan perangkat keras yang lebih kuat dan jika ukuran gambar terlalu rendah terlihat jelek pada layar HD.
Saya keluar dengan solusi yang bekerja dengan Samsung Galaxy S3 saya dan beberapa perangkat lain termasuk yang kurang kuat, dengan kualitas gambar yang lebih baik ketika perangkat yang lebih kuat digunakan.
Intinya adalah untuk menghitung memori maksimum yang dialokasikan untuk aplikasi pada perangkat tertentu, kemudian mengatur skala serendah mungkin tanpa melebihi memori ini. Berikut kodenya:
Saya mengatur memori maksimum yang digunakan oleh bitmap ini menjadi 25% dari memori maksimum yang dialokasikan, Anda mungkin perlu menyesuaikan ini dengan kebutuhan Anda dan memastikan bitmap ini dibersihkan dan tidak tinggal di memori ketika Anda selesai menggunakannya. Biasanya saya menggunakan kode ini untuk melakukan rotasi gambar (bitmap sumber dan tujuan) sehingga aplikasi saya perlu memuat 2 bitmap di memori pada saat yang sama, dan 25% memberi saya buffer yang baik tanpa kehabisan memori saat melakukan rotasi gambar.
Semoga ini bisa membantu seseorang di luar sana ..
sumber
Tersebut
OutofMemoryException
tidak dapat sepenuhnya diselesaikan dengan memanggilSystem.gc()
dan sebagainya.Dengan merujuk pada Siklus Hidup AktivitasStatus Aktivitas ditentukan oleh OS itu sendiri tergantung pada penggunaan memori untuk setiap proses dan prioritas setiap proses.
Anda dapat mempertimbangkan ukuran dan resolusi untuk masing-masing gambar bitmap yang digunakan. Saya sarankan untuk mengurangi ukuran, resample ke resolusi yang lebih rendah, lihat desain galeri (satu gambar PNG kecil, dan satu gambar asli.)
sumber
Kode ini akan membantu memuat bitmap besar dari drawable
sumber
Bitmap.Config.ARGB_565
? Jika kualitas tinggi tidak kritis.