Warum verwende ich SharedViewModel nicht für Fragmente?

Habr, hallo!

Die Aufgabe, die Interaktion zwischen Fragmenten zu organisieren, ist sehr verbreitet. ShareViewModel eignet sich auf den ersten Blick hervorragend dafür. Wir erstellen ein ViewModel mit owner = our activity, in dem unsere Fragmente angezeigt werden, und erhalten dieses ViewModel in jedem Fragment. weil Der Eigentümer des ViewModel ist die Aktivität. Die Fragmente erhalten dieselbe Instanz des ViewModel, mit der sie Daten, Aufrufmethoden usw. austauschen können. Hier ist der Link aus der Dokumentation .

Die folgende Abbildung zeigt das Interaktionsschema von 3 Fragmenten.

Bild

Jene. Was wir tun: In jedem Fragment erhalten wir das SharedViewModel der Fragmente, mit denen wir interagieren müssen ...

Und dies ist meiner Meinung nach nicht die beste Lösung. Weil:

  1. *VM. ViewModel View. ViewModel LiveData, View, .. ViewModel - , View.
  2. SharedViewModel — . , SharedViewModel , , . - .
  3. SharedViewModel, . , , .

SharedViewModel kann nur verwendet werden, wenn mehrere vollständig identische Fragmente mit denselben Daten vorhanden sind. In meiner Praxis gab es kein solches Szenario. Es kann zwei identische Fragmente geben, aber der Status des ViewModels ist unterschiedlich. Das SharedViewModel ist für sie ungültig.

SharedViewModel bringt eine Menge Probleme mit sich. Sie werden langsam verwirrt, alles ist mit Abhängigkeiten überwachsen, der Code ist kompliziert. Es ist viel einfacher zu arbeiten, wenn Fragment + ViewModel eine Black Box ist.

Welche Lösung kann angeboten werden?

Ein einfacher Dienst, mit dem jedes Fragment auf seine Weise interagiert.

Bild

Dieser Dienst muss in jedem ViewModel übergeben werden. Dank DI und Scope (Dagger, Koin, alle anderen) kann dies einfach und unkompliziert durchgeführt werden. Wenn der Dienst im Kontext einer Aktivität ausgeführt werden soll, erstellen Sie ihn im Bereich dieser Aktivität und übergeben Sie ihn an jedes ViewModel.

Sehen Sie, was passiert ist: Wir haben alle SharedViewModel aus Fragmenten entfernt. Jedes Fragment weiß jetzt nichts über die anderen Fragmente. Wenn wir diesem Schema ein neues Fragment hinzufügen möchten, müssen wir nur viewModel D mit unserem Service verbinden und fertig. Wenn das Fragment auf eine Änderung einer Eigenschaft des Dienstes reagieren soll, abonnieren Sie es einfach. Wir müssen die ViewModels anderer Leute nicht mehr verstehen. Und dieser Dienst ist viel einfacher als jedes ViewModel, es wird einfacher sein, den Dienst zu verstehen.

Es scheint, dass sich nicht so viele interagierende Fragmente auf einem Bildschirm befinden. Am Telefon - vielleicht. Auf dem Tablet - das kann man nicht mehr sagen. Und FragmentContainerView hilft bei der Verwendung von Fragmenten in beliebigen Layouts. Dies ist sehr praktisch, wenn die Anwendung viele gemeinsame Komponenten mit einem Lebenszyklus enthält.

Bonus: Wie erstelle ich Fragmente?


So: SomeFragment ()

Und was ist mit den Parametern?

Mit dem Aufkommen von ViewModel verwende ich keine Parameter. Ich übergebe nichts per Bundle an das Fragment (Android Studio bietet weiterhin an, ein Fragment mit Argumenten zu erstellen und ein Fragment mithilfe der statischen Methode zu erstellen). Ich verwende Safety NavArgs nicht für die Navigationskomponente .

All diese Dinge machen das Fragment konditioniert. Wir können ein solches Fragment beispielsweise nicht einfach zum ViewPager hinzufügen. Man muss sich überlegen, wie man die Parameter übergibt. Oder ein anderes Beispiel: Sie haben ein Fragment mit Parametern erstellt, arbeiten daran, die Daten haben sich geändert, das Fragment zeigt bereits etwas anderes. Wir haben die Gerätekonfiguration geändert (umgedreht), das Fragment wurde mit veralteten Parametern neu erstellt, während das ViewModel bereits andere Daten enthält. Und die Aktualisierung der Parameter usw. beginnt.

Ich habe das alles im ViewModel entfernt. Ich benutze den gleichen Dienst, über den ich die Parameter übergebe. Es funktioniert wie Safety NavArgs. ViewModel fordert vom Dienst Parameter nach dem Typ der Parameterklasse an. Nach dem erfolgreichen Abrufen des Parameters löscht der Dienst diese (funktioniert wie Push / Pop).

Dies löst sofort das Problem der Änderung der Konfiguration: Das Fragment wurde erneut erstellt, und das ViewModel enthält bereits die aktuellen Daten. Sie müssen sie lediglich mit der Ansicht verbinden.

Es gibt auch ein Problem beim Übergeben von Parametern durch das Bündel - dies ist ein Überschuss der zulässigen Menge. Wenn die übertragene Datenmenge mehr als 500 KB beträgt, kann die Anwendung aufgrund einer Ausnahme in Binder.java abstürzen. Dies führte zur Schaffung verschiedener Bibliotheken, die Parameter über SD übertragen, was im Vergleich zur Verwendung von RAM nicht sehr schnell ist.

Im Allgemeinen sind die Werkzeuge cool, alles ist flexibel, aber Sie müssen vorsichtig sein.

Das ist alles, danke fürs Zuschauen!

All Articles