2016-05-04 11 views
0

Ich bin erfahren genug, um Konfigurationsänderungen zu kennen. Ich weiß, wie man den Instanzzustand eines View, Activity, Fragment oder was auch immer speichert und wiederherstellt, und ich weiß, dass wir uns darauf verlassen sollten, anstatt einfach Objekte statisch zu machen.Statisches Muster zum Zurückhalten von Objekten durch Konfigurationsänderungen

Diese Frage ist über static Ness eines Feldes. In "reinem Java" dient die Deklaration eines Objekts als static dazu, dass es unter Instanzen geteilt wird. In dem Android-System, ein static Feld zu deklarieren ist auch eine schnelle Möglichkeit, es überleben Konfigurationsänderungen, wenn unsere Instanz neu erstellt und seine Felder sind gelöscht.

Beispiel:

public class FooFragment extends Fragment { 

    private static Object sObject; 

    public void onViewCreated(View view, Bundle savedInstanceState) { 
     if (savedInstanceState == null) { 
      sObject = new Object(); 
      sObject.toString(); 
     } else { 
      sObject.toString(); 
     } 
    } 

} 

In diesem Fall kann sObject initialisiert werden, wenn das Fragment erstellt und nur abgerufen, wenn das Fragment neu erstellt wird. Probleme treten auf, wenn unsere Klasse nicht selbst statisch ist, als Basisklasse konzipiert ist oder eine Klasse abstract ist.

public abstract class BaseFragment extends Fragment { 

    protected static Object sObject; 
} 

public class FooFragment extends BaseFragment { 

    public void onViewCreated(View view, Bundle savedInstanceState) { 
     if (savedInstanceState == null) { 
      sObject = new Object(); 
      sObject.toString(); 
     } else { 
      sObject.toString(); 
     } 
    } 
} 

public class BarFragment extends BaseFragment { 

    public void onViewCreated(View view, Bundle savedInstanceState) { 
     if (savedInstanceState == null) { 
      sObject = new Object(); 
      sObject.toString(); 
     } else { 
      sObject.toString(); 
     } 
    } 
} 

Nun sind beide FooFragment und BarFragment wird zugreifen (und impredictably verwenden), um die gleiche Instanz von sObject. Das ist der Punkt der Statik, aber nicht das, was wir wollen. Wir wollen FooFragment und haben ihre eigenen sObject; Wir wollen nur, dass es Konfigurationsänderungen und plattformgesteuerte Erholung überlebt.

Frage

Wie kann ich für dieses Ziel die Basisklasse entwerfen?

Das ist, was ich dachte, aber ich bin sicher, es gibt etwas Besseres.

public abstract class BaseFragment extends Fragment { 

    private static HashMap<String, Object> sObjects; 

    public void onViewCreated(View view, Bundle savedInstanceState) { 
     if (savedInstanceState == null) { 
      Object o = new Object(); 
      sObjects.put(getClass().getName(), o); 
     } 
    } 

    protected final Object getObject() { 
     return sObjects.get(getClass().getName()); 
    } 
} 

Grundsätzlich halte ich eine statische Karte, Indexierung von Kind Klassenname.

+3

"ein statisches Feld zu deklarieren ist auch ein schneller Weg, um Konfigurationsänderungen zu überleben" - wenn Sie eine Stack Overflow Frage nach der Technik stellen müssen, ist es nicht mehr "ein schneller Weg", IMHO. Ihr Ansatz riskiert Speicherlecks, und es ist unklar, was Sie gewinnen im Vergleich zur Verwendung eines beibehaltenen Fragments (oder des gespeicherten Instanzzustands "Bundle", für Dinge, die dort hineingehen können). – CommonsWare

+0

@CommonsWare Nun, ich habe meine Lösung gepostet, ich würde gerne wissen, ob es etwas aus der Sicht des Designs besser ist. Mein Objekt kann nicht gebündelt werden, und setRetainInstance() ist eine (meiner Meinung nach und in meinem Fall) schlechte Lösung für BaseFragments, ist aber keine Lösung für BaseViews. – natario

+0

Ich denke, ich verbringe etwa 60% meiner Entwicklungszeit damit, Zustandsrestaurationen auf "Plattform" -Weise zu konfigurieren, also weiß ich, wovon ich rede. Ich möchte diese statische Strategie für ein bestimmtes Objekt verwenden, das nicht auf standardmäßige Weise behandelt werden kann. – natario

Antwort

1

Im Grunde implementieren Sie einen globalen Cache. Die Tatsache, dass Sie es für Konfigurationsänderungen verwenden, ist nur ein Detail. Daher müssen Sie das Standardmaterial für globale Caches berücksichtigen. Betrachten Sie beispielsweise HashMap<String, WeakReference<Object>>. Wenn Sie das Objekt aufgrund eines Codierungsfehlers oder einer unbehandelten Ausnahme nicht aus der Datei HashMap entfernen können, ist die langfristige Auswirkung gering.

In Bezug auf weitere Android-spezifische Überlegungen sollte nichts, was in diesen Cache geht, konfigurationsabhängig sein, wie z. B. der Wert einer Zeichenfolge, die aus String-Ressourcen ausgewählt wurde. Diese müssen neu erstellt werden, da die Konfigurationsänderung ihren Wert beeinflussen kann.

Außerdem sollte nichts, das in diesen Cache gelangt, von der Umgebung vor der Konfigurationsänderung abhängig sein, z. B. Ansichten der früheren Aktivität, um Speicherlecks zu reduzieren.

Während Sie denken, dass beibehaltene Fragmente ungeeignet sind, können Sie sich die Implementierung oder die Implementierung anderer globaler Caches (z. B. Picassos Bildcache) ansehen, um weitere Ideen zu erhalten.

0

Ihre Methode funktioniert, wenn Sie eine kleine App haben.Es gibt jedoch einige Dinge, die dies erschweren können.

1. Speicherbedarf: Jede statische Instanz wird beibehalten, auch wenn Sie diesen Bildschirm nicht verwenden. Wie oben erwähnt, ist dies keine große Sache, wenn Ihre Anwendung klein ist, kann aber Probleme verursachen, wenn Ihre Anwendung wächst.

2. Testbarkeit: Testing statische Dinge sind nicht Spaß :(

Es kann einfache Möglichkeiten, Ihre Ziele zu erreichen

Option A Laden von DB Grundsätzlich so wenig Staat speichern als.. möglich (vielleicht ID der Daten, die Sie betrachten) und laden Daten auf Ausrichtung ändern.

Option B Machen Sie den Speicherzustand mit einer Bibliothek wie IcePick Sie einfacher kann Grundelemente speichern oder Kundenumsetzer für Objekte erstellen (z. Verwenden Sie GSON, um ein Objekt in JSON zu konvertieren.

Verwandte Themen