Obwohl ich ein sehr kleines Bild in einem Zeichenordner habe, erhalte ich diesen Fehler von den Benutzern. Und ich verwende keine Bitmap-Funktion im Code. Zumindest absichtlich :)
java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:683)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:513)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889)
at android.content.res.Resources.loadDrawable(Resources.java:3436)
at android.content.res.Resources.getDrawable(Resources.java:1909)
at android.view.View.setBackgroundResource(View.java:16251)
at com.autkusoytas.bilbakalim.SoruEkrani.cevapSecimi(SoruEkrani.java:666)
at com.autkusoytas.bilbakalim.SoruEkrani$9$1.run(SoruEkrani.java:862)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Laut diesem stackTrace erhalte ich diesen Fehler in dieser Zeile ('tv' ist eine Textansicht):
tv.setBackgroundResource(R.drawable.yanlis);
Worin besteht das Problem? Wenn Sie weitere Informationen zum Code benötigen, kann ich diese hinzufügen. Vielen Dank!
android
bitmap
out-of-memory
bitmapfactory
setbackground
Utku Soytaş
quelle
quelle
Antworten:
Sie können die Größe des Heapspeichers nicht dynamisch erhöhen, aber Sie können die Verwendung von Heap mithilfe von anfordern.
In
manifest.xml
können Sie in Ihrem Manifest diese Zeilen hinzufügen, die in bestimmten Situationen funktionieren.<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:largeHeap="true" android:supportsRtl="true" android:theme="@style/AppTheme">
Verwenden Sie die Methoden
getMemoryClass()
oder , um die verfügbare Speichergröße zur Laufzeit abzufragengetLargeMemoryClass()
.Wenn immer noch Probleme auftreten, sollte dies auch funktionieren
BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 8; mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options);
Wenn ein Wert> 1 festgelegt ist, wird der Decoder aufgefordert, das Originalbild zu unterabtasten und ein kleineres Bild zurückzugeben, um Speicherplatz zu sparen.
Dies ist die optimale Verwendung von BitmapFactory.Options.inSampleSize im Hinblick auf die Geschwindigkeit der Bildanzeige. In der Dokumentation wird die Verwendung von Werten mit einer Potenz von 2 erwähnt, daher arbeite ich mit 2, 4, 8, 16 usw.
Gehen wir näher auf die Bildabtastung ein:
Zum Beispiel lohnt es sich nicht, ein Bild mit 1024 x 768 Pixeln in den Speicher zu laden, wenn es irgendwann in einem Miniaturbild mit 128 x 128 Pixeln in einem Bild angezeigt wird
ImageView
.Um den Decoder zu sagen , das Bild unterabzutasten, eine kleinere Version in dem Speicher, Satz Laden
inSampleSize
zutrue
in IhremBitmapFactory.Options
Objekt. Beispielsweise erzeugt ein Bild mit einer Auflösung von 2100 x 1500 Pixel, das mit einer AuflösunginSampleSize
von 4 dekodiert wird, eine Bitmap von ungefähr 512 x 384. Das Laden in den Speicher verwendet 0,75 MB anstelle von 12 MB für das vollständige Image (unter der Annahme einer Bitmap-Konfiguration vonARGB_8888
). Hier ist eine Methode zum Berechnen eines Stichprobengrößenwerts, der eine Zweierpotenz basierend auf einer Zielbreite und -höhe ist:public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
Um diese Methode zu verwenden, dekodieren Sie zuerst mit
inJustDecodeBounds
set totrue
, übergeben Sie die Optionen und dekodieren Sie dann erneut mit dem neueninSampleSize
Wert undinJustDecodeBounds
setzen Sie auffalse
:public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
Diese Methode erleichtert das Laden einer Bitmap beliebig großer Größe in eine Bitmap mit
ImageView
einer Miniaturansicht von 100 x 100 Pixel, wie im folgenden Beispielcode gezeigt:mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
Sie können einen ähnlichen Prozess ausführen, um Bitmaps aus anderen Quellen zu dekodieren, indem Sie die entsprechende
BitmapFactory.decode*
Methode nach Bedarf ersetzen .Ich fand diesen Code auch interessant:
private Bitmap getBitmap(String path) { Uri uri = getImageUri(path); InputStream in = null; try { final int IMAGE_MAX_SIZE = 1200000; // 1.2MP in = mContentResolver.openInputStream(uri); // Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(in, null, o); in.close(); int scale = 1; while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) { scale++; } Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight); Bitmap bitmap = null; in = mContentResolver.openInputStream(uri); if (scale > 1) { scale--; // scale to max possible inSampleSize that still yields an image // larger than target o = new BitmapFactory.Options(); o.inSampleSize = scale; bitmap = BitmapFactory.decodeStream(in, null, o); // resize to desired dimensions int height = bitmap.getHeight(); int width = bitmap.getWidth(); Log.d(TAG, "1th scale operation dimenions - width: " + width + ", height: " + height); double y = Math.sqrt(IMAGE_MAX_SIZE / (((double) width) / height)); double x = (y / height) * width; Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x, (int) y, true); bitmap.recycle(); bitmap = scaledBitmap; System.gc(); } else { bitmap = BitmapFactory.decodeStream(in); } in.close(); Log.d(TAG, "bitmap size - width: " +bitmap.getWidth() + ", height: " + bitmap.getHeight()); return bitmap; } catch (IOException e) { Log.e(TAG, e.getMessage(),e); return null; }
So verwalten Sie den Speicher Ihrer App: Link
Es ist keine gute Idee,
android:largeHeap="true"
hier den Auszug aus Google zu verwenden, der dies erklärt:Nachdem ich exkret gearbeitet habe,
out of memory errors
würde ich sagen, dass es keine Sünde ist, dies dem Manifest hinzuzufügen, um das Problem zu vermeidenÜberprüfen des App-Verhaltens auf der Android Runtime (ART)
Die Android-Laufzeit (ART) ist die Standardlaufzeit für Geräte mit Android 5.0 (API-Stufe 21) und höher. Diese Laufzeit bietet eine Reihe von Funktionen, die die Leistung und Glätte der Android-Plattform und -Apps verbessern. Weitere Informationen zu den neuen Funktionen von ART finden Sie unter Einführung in ART .
Einige Techniken, die auf Dalvik funktionieren, funktionieren jedoch nicht auf ART. In diesem Dokument erfahren Sie, worauf Sie bei der Migration einer vorhandenen App achten müssen, um mit ART kompatibel zu sein. Die meisten Apps sollten nur funktionieren, wenn sie mit ART ausgeführt werden.
Beheben von Problemen mit der Garbage Collection (GC)
Unter Dalvik finden es Apps häufig nützlich, System.gc () explizit aufzurufen, um die Garbage Collection (GC) aufzufordern. Dies sollte bei ART weitaus weniger erforderlich sein, insbesondere wenn Sie die Garbage Collection aufrufen, um Vorkommen vom Typ GC_FOR_ALLOC zu verhindern oder die Fragmentierung zu verringern. Sie können überprüfen, welche Laufzeit verwendet wird, indem Sie System.getProperty ("java.vm.version") aufrufen. Wenn ART verwendet wird, beträgt der Wert der Eigenschaft "2.0.0" oder höher.
Darüber hinaus wird im Android Open-Source Project (AOSP) ein komprimierender Garbage Collector entwickelt, um die Speicherverwaltung zu verbessern. Aus diesem Grund sollten Sie die Verwendung von Techniken vermeiden, die mit der Komprimierung von GC nicht kompatibel sind (z. B. das Speichern von Zeigern auf Objektinstanzdaten). Dies ist besonders wichtig für Apps, die das Java Native Interface (JNI) verwenden. Weitere Informationen finden Sie unter Verhindern von JNI-Problemen.
Verhindern von JNI-Problemen
Das JNI von ART ist etwas strenger als das von Dalvik. Es ist eine besonders gute Idee, den CheckJNI-Modus zu verwenden, um häufige Probleme zu erkennen. Wenn Ihre App C / C ++ - Code verwendet, sollten Sie den folgenden Artikel lesen:
Sie können auch nativen Speicher ( NDK & JNI ) verwenden, sodass Sie die Beschränkung der Heap-Größe tatsächlich umgehen.
Hier sind einige Beiträge dazu:
So speichern Sie Bitmaps im nativen Speicher
https://stackoverflow.com/a/9428660/1761003
JNI-Bitmap-Operationen zur Vermeidung von OOM bei Verwendung großer Bilder
und hier ist eine Bibliothek dafür gemacht:
quelle
Gattsu
:"For example, it’s not worth loading a 1024x768 pixel image into memory if it will eventually be displayed in a 128x96 pixel thumbnail in an ImageView."
Ich sehe nur zwei Möglichkeiten:
quelle
Sie sollten einen LRU-Cache-Manager implementieren, wenn Sie mit Bitmap arbeiten
http://developer.android.com/reference/android/util/LruCache.html http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html Wann sollte ich eine Bitmap mit LRUCache recyceln?
ODER
Verwenden Sie eine Ebenenbibliothek wie Universal Image Loader:
https://github.com/nostra13/Android-Universal-Image-Loader
EDIT:
Wenn ich mich jetzt mit Bildern und meistens mit Bitmap beschäftige, verwende ich Glide, mit dem Sie ein Glide-Modul und einen LRUCache konfigurieren können
https://github.com/bumptech/glide
quelle
Einige Hinweise zur Behandlung solcher Fehler / Ausnahmen für Android Apps:
Aktivitäten und Anwendungen haben Methoden wie:
Für das Tag im Manifest kann das Attribut 'largeHeap' auf TRUE gesetzt sein, wodurch mehr Heap für die App-Sandbox angefordert wird.
Verwalten des In-Memory-Caching und des Festplatten-Caching:
Verwendung von WeakReference, SoftReference zur Erstellung von Java-Instanzen, speziell für Dateien.
Wenn so viele Bilder vorhanden sind, verwenden Sie die richtige Bibliothek / Datenstruktur, die den Speicher verwalten kann, verwenden Sie die Abtastung der geladenen Bilder und übernehmen Sie das Festplatten-Caching.
Behandeln Sie die OutOfMemory-Ausnahme
Befolgen Sie die Best Practices für die Codierung
Minimieren Sie den Aktivitätsstapel, z. B. die Anzahl der Aktivitäten im Stapel (halten Sie nicht alles auf Kontext / Aktivität)
Minimieren Sie die Verwendung von Statik und vielen weiteren Singletons.
Achten Sie auf die Grundspeicher des Betriebssystems
Rufen Sie GC.Collect () manchmal manuell auf, wenn Sie sicher sind, dass kein In-Memory-Caching mehr erforderlich ist.
quelle
Wenn Sie diesen Fehler java.lang.OutOfMemoryError erhalten, ist dies das häufigste Problem, das in Android auftritt. Dieser Fehler wird von der Java Virtual Machine (JVM) ausgelöst, wenn ein Objekt aufgrund fehlenden Speicherplatzes nicht zugewiesen werden kann.
Versuchen Sie dies
android:hardwareAccelerated="false" , android:largeHeap="true"
in Ihrer manifest.xml-Datei unter Anwendung wie folgt:<application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:hardwareAccelerated="false" android:largeHeap="true" />
quelle
android:hardwareAccelerated="false"
? Wenn ich es wahr mache, was passiert dann?android:largeHeap="true"
habe den Fehler nicht behobenIn meinem Fall wurde dieser Fehler angezeigt, nachdem ich dem Ordner "Drawable" ein Symbol / Bild hinzugefügt hatte, indem ich SVG in einen Vektor konvertierte. Gehen Sie einfach zur XML-Symboldatei und legen Sie kleine Zahlen für die Breite und Höhe fest
android:width="24dp" android:height="24dp" android:viewportWidth="3033" android:viewportHeight="3033"
quelle