1389 Stimmen

Seltsames OutOfMemory-Problem beim Laden eines Bildes in ein Bitmap-Objekt

Ich habe eine ListView mit ein paar Bildschaltflächen in jeder Zeile. Wenn der Benutzer auf die Listenzeile klickt, wird eine neue Aktivität gestartet. Aufgrund eines Problems mit dem Kamera-Layout musste ich meine eigenen Registerkarten erstellen. Die Aktivität, die für das Ergebnis gestartet wird, ist eine Karte. Wenn ich auf meine Schaltfläche klicke, um die Bildvorschau zu starten (Laden eines Bildes von der SD-Karte), kehrt die Anwendung von der Aktivität zurück zur ListView Aktivität zum Ergebnis-Handler, um meine neue Aktivität, die nichts anderes als ein Bild-Widget ist, neu zu starten.

Die Bildvorschau auf der Seite ListView wird mit dem Cursor durchgeführt und ListAdapter . Dies macht es ziemlich einfach, aber ich bin mir nicht sicher, wie ich ein verkleinertes Bild (d.h. kleinere Bitgröße nicht Pixel als die src für die Bild-Schaltfläche im laufenden Betrieb. Also habe ich einfach die Größe des Bildes, das von der Handykamera kam, geändert.

Das Problem ist, dass ich eine OutOfMemoryError wenn er versucht, zurückzugehen und die 2. Aktivität erneut zu starten.

  • Gibt es eine Möglichkeit, den Listenadapter einfach zeilenweise zu erstellen, wobei ich die Größe während des Betriebs ändern kann ( bitweise )?

Dies wäre wünschenswert, da ich auch einige Änderungen an den Eigenschaften der Widgets/Elemente in jeder Zeile vornehmen muss, da ich aufgrund des Fokusproblems nicht in der Lage bin, eine Zeile mit dem Touchscreen auszuwählen. ( Ich kann Rollerball verwenden. )

  • Ich weiß, dass ich die Größe außerhalb des Bandes ändern und mein Bild speichern kann, aber das ist nicht wirklich das, was ich tun möchte, aber ein Beispielcode dafür wäre schön.

Sobald ich das Bild auf dem Bildschirm deaktiviert habe ListView hat es wieder gut funktioniert.

Zu Ihrer Information: So habe ich es gemacht:

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);

どこ R.id.imagefilename es un ButtonImage .

Hier ist mein LogCat:

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 

Ich habe auch einen neuen Fehler beim Anzeigen eines Bildes:

22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

9 Stimmen

Ich löste dies, indem ich Bitmap.decodeStream oder decodeFile vermied und die Methode BitmapFactory.decodeFileDescriptor verwendete.

2 Stimmen

Ich auch konfrontiert ähnliches Problem paar Wochen zurück und ich löste es durch Skalierung Bilder bis zu optimalen Punkt. Ich habe komplette Ansatz in meinem Blog geschrieben codingjunkiesforum.wordpress.com/2014/06/12/ und lud ein komplettes Beispielprojekt mit OOM-anfälligem Code im Vergleich zu OOM-Proof-Code aufhttps://github.com/shailendra123/BitmapHandlingDemo hoch.

2 Stimmen

Vollständige Lösung .. stackoverflow.com/a/24135283/294884

15voto

Jesse Punkte 2604

Ich habe den ganzen Tag damit verbracht, diese Lösungen zu testen, und das Einzige, was für mich funktioniert hat, sind die oben genannten Ansätze für das Abrufen des Bildes und den manuellen Aufruf der GC, von dem ich weiß, dass er nicht notwendig sein soll, aber es ist das Einzige, was funktioniert hat, als ich meine App unter schweren Lasttests zwischen Aktivitäten umgeschaltet habe. Meine App hat eine Liste von Miniaturbildern in einer Listenansicht in (sagen wir Aktivität A) und wenn man auf eines dieser Bilder klickt, gelangt man zu einer anderen Aktivität (sagen wir Aktivität B), die ein Hauptbild für dieses Element zeigt. Wenn ich zwischen den beiden Aktivitäten hin und her wechseln würde, würde ich schließlich den OOM-Fehler erhalten und die App würde zwangsweise geschlossen werden.

Wenn ich die Hälfte der Listenansicht erreicht hatte, stürzte sie ab.

Nun, wenn ich die folgenden in Aktivität B zu implementieren, kann ich durch die gesamte listview ohne Problem gehen und halten Sie gehen und gehen und gehen ... und seine viel schnell.

@Override
public void onDestroy()
{   
    Cleanup();
    super.onDestroy();
}

private void Cleanup()
{    
    bitmap.recycle();
    System.gc();
    Runtime.getRuntime().gc();  
}

14voto

matsoftware Punkte 766

Meine 2 Cents: Ich habe meine OOM-Fehler mit Bitmaps gelöst, indem ich:

a) Skalierung meiner Bilder um den Faktor 2

b) Verwendung Picasso Bibliothek in meinem benutzerdefinierten Adapter für eine ListView, mit einem Aufruf in getView wie diesem: Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);

14voto

vineet Punkte 279

Dieser Code hilft, große Bitmaps aus Drawable zu laden

public class BitmapUtilsTask extends AsyncTask<Object, Void, Bitmap> {

    Context context;

    public BitmapUtilsTask(Context context) {
        this.context = context;
    }

    /**
     * Loads a bitmap from the specified url.
     * 
     * @param url The location of the bitmap asset
     * @return The bitmap, or null if it could not be loaded
     * @throws IOException
     * @throws MalformedURLException
     */
    public Bitmap getBitmap() throws MalformedURLException, IOException {       

        // Get the source image's dimensions
        int desiredWidth = 1000;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

        int srcWidth = options.outWidth;
        int srcHeight = options.outHeight;

        // Only scale if the source is big enough. This code is just trying
        // to fit a image into a certain width.
        if (desiredWidth > srcWidth)
            desiredWidth = srcWidth;

        // Calculate the correct inSampleSize/scale value. This helps reduce
        // memory use. It should be a power of 2
        int inSampleSize = 1;
        while (srcWidth / 2 > desiredWidth) {
            srcWidth /= 2;
            srcHeight /= 2;
            inSampleSize *= 2;
        }
        // Decode with inSampleSize
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inSampleSize = inSampleSize;
        options.inScaled = false;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.inPurgeable = true;
        Bitmap sampledSrcBitmap;

        sampledSrcBitmap =  BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

        return sampledSrcBitmap;
    }

    /**
     * The system calls this to perform work in a worker thread and delivers
     * it the parameters given to AsyncTask.execute()
     */
    @Override
    protected Bitmap doInBackground(Object... item) {
        try { 
          return getBitmap();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

14voto

Raju yourPepe Punkte 2819

Diese OutofMemoryException nicht vollständig gelöst werden kann, indem die System.gc() und so weiter.

Durch den Verweis auf die Lebenszyklus der Aktivität

Die Aktivitätszustände werden vom Betriebssystem selbst in Abhängigkeit von der Speichernutzung für jeden Prozess und der Priorität jedes Prozesses festgelegt.

Sie können die Größe und die Auflösung für jedes der verwendeten Bitmap-Bilder berücksichtigen. Ich empfehle, die Größe zu reduzieren, auf eine niedrigere Auflösung umzurechnen, sich auf das Design der Galerien zu beziehen (ein kleines Bild PNG, und ein Originalbild.)

7voto

Exceptional Punkte 2926
BitmapFactory.Options options = new Options();
options.inSampleSize = 32;
//img = BitmapFactory.decodeFile(imageids[position], options);

Bitmap theImage = BitmapFactory.decodeStream(imageStream,null, options);
Bitmap img=theImage.copy(Bitmap.Config.RGB_565,true);
theImage.recycle();
theImage = null;
System.gc();
//ivlogdp.setImageBitmap(img);
Runtime.getRuntime().gc();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X