2013-11-22 6 views
11

Ich wurde nach gerade diesen Artikel auf, wie Speicherlecks zu vermeiden: android developer blog das Code-Snippet verwendet Es folgt:Warum verliert Android aufgrund statischer Drawable Speicher, wenn der Rückruf zurückgesetzt wird?

private static Drawable sBackground; 

@Override 
protected void onCreate(Bundle state) { 
    super.onCreate(state); 

    TextView label = new TextView(this); 
    label.setText("Leaks are bad"); 

    if (sBackground == null) { 
    sBackground = getDrawable(R.drawable.large_bitmap); 
    } 
    label.setBackgroundDrawable(sBackground); 

    setContentView(label); 
} 

Es wird gesagt, dass die ziehbar einen Rückruf Bezug auf Textview hat (und indirekt auf die Aktivität) ; was bei Rotation erhalten bleibt - und daher Speicherleck.

Meine Anfrage ist, dass nicht die Rückruf der ziehbar auf Rotation zurückgesetzt werden - es hält, die neuen Textview bekommen würde (die den neuen Kontext halten wird) .. also die vorherigen Instanzen von Textview/Kontext erlaubt zu sein GC'ed.

EDIT: Die Antworten, die ich bekomme, sind auf, wie man das Problem "löst" - ich suche nicht dafür! Bitte lesen Sie die Abfrage erneut. Ich füge mehr Details hinzu. Wenn Aktivität gestartet wird, die Referenzen sind:

Drawable1 -> TextView1 -> Activity1

Wenn gedreht wird, Activity1 und TextView1 werden zerstört, aber nicht Drawable1

Drawable1 -> TextView2 -> Aktivität2

Dies bedeutet Aktivität1 a nd TextView1 sind frei zu GC'ed - wie kein anderes Objekt einen Verweis auf sie hat. Also, was ist undicht?

Bin ich falsch in diesem Verständnis? Oder kann das Drawable mehrere Ansichten als Callbacks haben? (Mit Blick auf den Quellcode sehe ich keine Liste von Rückrufen auf Drawable).

+0

Wenn Sie Ihr Layout bei der Rotation nicht ändern, ist es eine gute Sache, die Rotation anders zu behandeln: ohne Neubildung der Aktivität (es ist möglich). Das wird deine Probleme lösen. Eine andere Sache mit Speicherlecks ist, dass es sich lohnt, den Hintergrund in 'onDestroy' zu entfernen. –

+0

Danke, aber ich bin besorgt, warum das Leck im ersten Fall passiert. Ich verstehe, wie man das Problem löst. – SlowAndSteady

+0

Eine Rotationsaktivität wird "neu erstellt", sodass Ihre vorherige Ansicht/Ihr Bild mit dem vorherigen Aktivitätskontext verbunden ist - Sie haben also ein Speicherleck. Wenn Sie in onDestroy aufräumen() wird es das Problem beheben –

Antwort

7

Wenn Sie das Gerät drehen, die gleiche MyActivity Klasse (oder was auch immer Sie nennen es gab) neu erstellt wird, ist der Rückruf überschrieben und das Leck existiert bis zur nächsten GC. Das Problem liegt darin, dass Sie zu einer anderen Aktivität navigieren und einen Verweis auf die alte beibehalten. Heute wird dies gemildert, da die setCallback jetzt den Rückruf in einem WeakReference speichert, wie Sie in current Drawable code sehen können, aber es war eine starke Referenz once (Suche nach setCallback(Callback cb)). Wie auch immer, Sie haben recht, wenn Sie nur in eine Aktivität schauen, wird der Callback nach dem Drehen zurückgesetzt.

(bearbeiten, Absatz angefügt): Zum Beispiel: MainAcivity @ 1 ist die erste Instanz. Wenn Sie sich drehen, wird es zerstört und eine neue MainActivity @ 2 wird erstellt. Zuerst gibt es ein Leck, aber sobald sDrawable neu zugewiesen wird, kann MainActivity @ 1 kostenlos gesammelt werden und es gibt kein Problem. Angenommen, Sie navigieren nicht zu Rotieren, sondern zu SecondActivity. Jetzt, sDrawable ist nur für MainActivity und immer noch eine Referenz auf MainActivity @ 2, so dass es leckt.

Sehen Sie diesen Code:

package com.douglasdrumond.leaky; 

import android.os.Bundle; 
import android.app.Activity; 
import android.graphics.drawable.Drawable; 
import android.widget.TextView; 

public class MainActivity extends Activity { 
    private static Drawable sBackground; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     TextView label = new TextView(this); 
     System.gc(); 
     long memory = Runtime.getRuntime().totalMemory() 
       - Runtime.getRuntime().freeMemory(); 
     label.setText("Memory: " + memory/1024f); 

     if (sBackground == null) { 
      sBackground = getResources().getDrawable(R.drawable.large_bitmap); 
     } 
     label.setBackgroundDrawable(sBackground); 

     setContentView(label); 
    } 

} 

klar, Speichernutzung erhöht nicht dreht.

+0

Danke @Douglas, aber das löst meine Abfrage nicht. Können Sie die bearbeitete Abfrage lesen? – SlowAndSteady

+0

@Raj, Ich habe den Satz hervorgehoben, als ich vorher mit Ihnen übereingestimmt habe und einen weiteren Absatz hinzugefügt habe. Es gibt kein Leck, wenn Sie in derselben Aktivität bleiben (oder, mit anderen Worten, das Leck ist temporär), gerade wenn Sie zu einer anderen Aktivität navigieren. Der Code dient nicht zur Lösung des Problems, sondern zur Hervorhebung. Bitte aufmerksam lesen. –

+1

Danke @Douglas Drumond, das habe ich nicht herausgefunden! – SlowAndSteady

Verwandte Themen