Entspricht das Verhalten der Funktionsweise von Aktivitäten? Zum Beispiel funktioniert es bei Aktivitäten folgendermaßen:
Aktivität A startet Aktivität B , während B auf dem Bildschirm angezeigt wird, kann das System A aus dem Speicher entfernen, wenn dies vom System benötigt wird. Wenn Sie auf ZURÜCK drücken, wird A im Speicher neu erstellt, als ob es überhaupt nicht verlassen worden wäre.
Ich habe nach einer klaren Erklärung gesucht, was mit Fragmenten in Bezug auf das Gedächtnis passiert, und nichts gefunden. Funktioniert es genauso? Zum Beispiel:
Aktivität C enthält Fragment F im Layout. Dann wird F irgendwann durch Fragment G ersetzt , aber F wird in seinem hinteren Stapel gehalten.
Will F Aufenthalt im Speicher , bis der C getötet wird oder kann sie vom System entfernt werden , je nach Bedarf?
Ich frage mich wirklich, ob ich das Risiko habe, dass mir der Speicher ausgeht, wenn ich einen Stapel komplizierter Fragmente in einer einzelnen Aktivität habe.
quelle
Antworten:
Schauen Sie sich das an: BackStackRecord.Op.fragment
So werden Fragmente im Backstack gespeichert. Notieren Sie sich die Live - Referenz, weder
WeakReference
nochSoftReference
werden dort verwendet.Nun dies: FragmentManagerImpl.mBackStack
Dort speichert der Manager den Backstack. Einfach
ArrayList
, auch keine WRs oder SRs.Und zum Schluss: Activity.mFragments
Das ist der Verweis auf den Fragmentmanager.
GC kann nur Objekte sammeln, die keine Live-Referenzen haben (von keinem Thread aus erreichbar). Das heißt, bis Ihre Aktivität zerstört ist (und somit die
FragmentManager
Referenz weg ist), kann GC keine der Fragmente im hinteren Stapel sammeln .Beachten Sie, dass bei Zerstörung der Aktivität und Beibehaltung des Status (z. B. wenn Sie das Gerät in den Querformatmodus versetzen) keine tatsächlichen
Fragment
Objekte im Stapel beibehalten werden, sondern nur deren Status - Fragment.FragmentState- Objekte, dh tatsächliche Fragmente im hinteren Stapel -Erstellt jedes Mal, wenn eine Aktivität mit beibehaltenem Status neu erstellt wird.Hoffe das hilft.
PS Kurz gesagt: Ja, Sie können nicht genügend Speicher haben, indem Sie
Fragments
dem Backstack hinzufügen und zu viele Ansichten hinzufügen, um die Hierarchie anzuzeigen.UPD In Ihrem Beispiel bleibt F im Speicher, bis C getötet wird. Wenn C getötet und dann mit einer anderen Konfiguration wiederbelebt wird, wird F auch in einem anderen Objekt zerstört und wiedergeboren. Der Speicherbedarf von F bleibt also bestehen, bis C den Status verliert oder der Rückstapel gelöscht wird.
quelle
major allocations
?Bitmap
s. Wenn Ihr Fragment ein paar Grundelemente oder Durchschnittsgrößen enthältString
, ist das wahrscheinlich in Ordnung. Entsorgen Sie jedoch mehrere Instanzen, die Sie über die Prozessspeicherobergrenze bringen würden.Fragment
Instanz in den Backstack gestellt wird, wird sie nicht zerstört. DaheronDestroyView()
sollten alle Ansichtsreferenzen, über die sie verfügt , immer auf Null gesetzt werden. Andernfalls wird verhindert, dass die toten Ansichten GCed werden. Nicht-Backstack-Fragmente (siehesetRetainInstance(true)
) werden auch dann nicht zerstört, wenn sieActivity
neu erstellt werden. Wenn Sie also Ansichtsreferenzen beibehalten , können Sie ein Ganzes verlierenActivity
. Normalerweise geschieht dies jedoch nicht, da in 99% der Fälle die Ansichtsreferenzen aktualisiert werden, inonCreateView()
denen die Actvity-Neuerstellung aufgerufen wird. Danach verweisen die Referenzen trotzdem auf neue Ansichten.Es tut mir leid, dass ich Ihnen keine offizielle Informationsquelle zur Verfügung stellen konnte, aber ich war auch neugierig zu sehen, was passieren würde, und habe beschlossen, es zu testen. Und nach meinen Tests laufen Sie Gefahr, dass Ihnen der Speicher ausgeht.
Ich musste eine unglaubliche Menge an Fragmenten (mehr als einhundert) in eine for-Schleife
OutOfMemoryError
einfügen, damit dies geschah, aber es geschah. Beim Überprüfen meiner Protokolle konnte ich feststellen, dass dieonCreate()
undonCreateView()
-Methoden häufig aufgerufenonSaveInstance()
wurdenonPause()
undonDestroy
überhaupt nicht aufgerufen wurden.Als Referenz habe ich die Fragmente wie folgt zum Backstack hinzugefügt:
getSupportFragmentManager().beginTransaction().add(R.id.scene_fragment_container, mSceneFragment).addToBackStack("FOOBAR").commit();
Und die Fragmente, die ich hinzufügte, waren etwas einfach: ein
ImageView
, einEditText
, ein PaarTextViews
, einSeekBar
und einListView
.Aber es sei denn, Sie haben eine große Datenmenge im Speicher, sollte dies kein Problem sein.
Später habe ich versucht, nur 50 zum Backstack hinzuzufügen, die App zu beenden und neu zu starten. Und wie ich gehofft / erraten habe, wurden alle Fragmente wiederhergestellt (und die Methoden
onSaveInstance()
undonPause()
aufgerufen), sodass meine Lebenszyklusimplementierung nicht das Problem war, das denOutOfMemoryError
Brand verursachte.quelle
Von developer.android.com/guide/topics/fundamentals/fragments.html
Ein Fragment muss immer in eine Aktivität eingebettet sein, und der Lebenszyklus des Fragments wird direkt vom Lebenszyklus der Hostaktivität beeinflusst. Wenn zum Beispiel die Aktivität angehalten wird, sind alle Fragmente darin, und wenn die Aktivität zerstört wird, sind auch alle Fragmente darin. Während eine Aktivität ausgeführt wird (sie befindet sich im wieder aufgenommenen Lebenszykluszustand), können Sie jedes Fragment unabhängig voneinander bearbeiten, z. B. hinzufügen oder entfernen. Wenn Sie eine solche Fragmenttransaktion ausführen, können Sie sie auch einem von der Aktivität verwalteten Backstack hinzufügen. Jeder Backstack-Eintrag in der Aktivität ist eine Aufzeichnung der aufgetretenen Fragmenttransaktion. Mit dem Backstack kann der Benutzer eine Fragmenttransaktion umkehren (rückwärts navigieren), indem er die Taste BACK drückt.
quelle
Ja, Ihnen kann der Speicherplatz ausgehen und zu viele Fragmente in einer einzelnen Aktivität erstellen. Die Fragmente werden nur zerstört, wenn die enthaltende Aktivität ist.
quelle