webentwicklung-frage-antwort-db.com.de

Teilen Sie ViewModel zwischen Fragmenten, die sich in unterschiedlichen Aktivitäten befinden

Ich habe ein ViewModel namens SharedViewModel:

public class SharedViewModel<T> extends ViewModel {

    private final MutableLiveData<T> selected = new MutableLiveData<>();


    public void select(T item) {
        selected.setValue(item);
    }

    public LiveData<T> getSelected() {
        return selected;
    }
}

Ich implementiere es basierend auf dem SharedViewModel-Beispiel auf der Google Arch ViewModel-Referenzseite: 

https://developer.Android.com/topic/libraries/architecture/viewmodel.html#sharing_data_between_fragments

Es ist sehr üblich, dass zwei oder mehr Fragmente in einer Aktivität miteinander kommunizieren müssen. Dies ist nie trivial als beide Fragmente müssen einige Schnittstellenbeschreibungen und den Eigentümer definieren Aktivität muss die beiden miteinander verbinden. Darüber hinaus müssen beide Fragmente behandeln den Fall, in dem das andere Fragment noch nicht erstellt wurde oder nicht sichtbar.

Ich habe zwei Fragmente namens ListFragment und DetailFragment

Bis jetzt habe ich diese zwei Fragmente in einem sogenannten MasterActivity verwendet. Und alles hat gut funktioniert. 

Ich habe das ViewModel in ListFragment erhalten und den Wert für DetailFragment ausgewählt.

mStepSelectorViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

Jetzt muss ich jedoch, dass in bestimmten Fällen ListFragment (ein Layout für eine andere Gerätekonfiguration) zu einer anderen Aktivität mit dem Namen DetailActivity hinzugefügt wird. Gibt es eine Möglichkeit, das obige Beispiel ähnlich zu machen? 

12
alexpfx

Etwas spät, aber Sie können dies mit einer gemeinsam genutzten ViewModelStore erreichen. Fragmente und Aktivitäten implementieren die ViewModelStoreOwner-Schnittstelle. In diesen Fällen haben Fragmente einen Speicher pro Instanz und Aktivitäten speichern ihn in einem statischen Member (ich denke, damit Konfigurationsänderungen überleben können).

Gehen Sie zurück zu der freigegebenen ViewModelStore. Sagen Sie beispielsweise, dass Sie möchten, dass es sich um Ihre Anwendungsinstanz handelt. Sie benötigen Ihre Anwendung, um ViewModelStoreOwner zu implementieren. 

class MyApp: Application(), ViewModelStoreOwner {
    private val appViewModelStore: ViewModelStore by lazy {
        ViewModelStore()
    }

    override fun getViewModelStore(): ViewModelStore {
        return appViewModelStore
    }
}

In den Fällen, in denen Sie wissen, dass Sie ViewModels zwischen Aktivitätsgrenzen teilen müssen, führen Sie so etwas aus.

val viewModel = ViewModelProvider(myApp, viewModelFactory).get(CustomViewModel::class.Java)

Jetzt wird der in Ihrer App definierte Store verwendet. Auf diese Weise können Sie ViewModels freigeben.

Sehr wichtig. Da in diesem Beispiel die Variable ViewModels in Ihrer Anwendungsinstanz lebt, werden sie nicht zerstört, wenn das Fragment/die Aktivität, die sie verwendet, zerstört werden. Sie müssen sie daher mit dem Lebenszyklus des letzten Fragments/der letzten Aktivität verknüpfen, die sie verwenden wird, oder sie manuell zerstören.

8
mikehc

Nun, ich habe zu diesem Zweck eine Bibliothek mit dem Namen Vita erstellt. Sie können ViewModels zwischen Aktivitäten und sogar Fragmenten mit verschiedenen Host-Aktivitäten teilen:

val myViewModel = vita.with(VitaOwner.Multiple(this)).getViewModel<MyViewModel>()

Das auf diese Weise erzeugte ViewModel bleibt am Leben, bis sein letztes LifeCycleOwner zerstört wird.

Sie können auch ViewModels mit Anwendungsbereich erstellen:

val myViewModel = vita.with(VitaOwner.None).getViewModel<MyViewModel>()

Und diese Art von ViewModel wird gelöscht, wenn der Benutzer die App schließt

Probieren Sie es aus und lassen Sie mich freundlich Ihr Feedback wissen: https://github.com/FarshadTahmasbi/Vita

2

sie können factory verwenden, um Viewmodel zu erstellen, und dieser Faktor gibt ein einzelnes Objekt des Ansichtsmodells zurück. Als:

class ViewModelFactory() : ViewModelProvider.Factory {

override fun create(modelClass: Class): T {
    if (modelClass.isAssignableFrom(UserProfileViewModel::class.Java)) {
    val key = "UserProfileViewModel"
    if(hashMapViewModel.containsKey(key)){
        return getViewModel(key) as T
    } else {
        addViewModel(key, UserProfileViewModel())
        return getViewModel(key) as T
    }
    }
    throw IllegalArgumentException("Unknown ViewModel class")
}

companion object {
    val hashMapViewModel = HashMap<String, ViewModel>()
    fun addViewModel(key: String, viewModel: ViewModel){
        hashMapViewModel.put(key, viewModel)
    }
    fun getViewModel(key: String): ViewModel? {
        return hashMapViewModel[key]
    }
}
}

In Aktivität:

viewModelFactory = Injection.provideViewModelFactory(this)

// Initialize Product View Model
userViewModel = ViewModelProviders.of(this, viewModelFactory).get(
UserProfileViewModel::class.Java)`

Dadurch wird nur ein einzelnes Objekt von UserProfileViewModel bereitgestellt, das Sie für Aktivitäten freigeben können.

2
Munish Thakur

Wenn Sie ein ViewModel möchten, das von allen Ihren Aktivitäten gemeinsam genutzt wird (im Gegensatz zu einigen anderen), dann Warum speichern Sie nicht das, was Sie in diesem ViewModel -Objekt in Ihrer Application-Klasse speichern möchten?

Der beim letzten Google I/O präsentierte Trend scheint darin zu bestehen, das Konzept der Aktivitäten zugunsten von Apps mit einer einzelnen Aktivität, die viele Fragmente enthalten, aufzugeben Früher musste eine Schnittstelle .... implementieren, so dass diese Annäherung nicht mehr für riesige und unbeschreibliche Aktivitäten sorgt.

1
Marcus Wolschon

Ich denke, wir werden immer noch mit dem MVVM-Framework auf Android .. verwechselt .. Für eine andere Aktivität, verwechseln Sie nicht, weil es unbedingt das gleiche sein muss, warum?

Dies ist sinnvoll, wenn dieselbe Logik vorhanden ist (auch wenn die Logik in anderen nützlichen Klassen noch abstrakt sein könnte) oder wenn die Ansicht in XML nahezu identisch ist.

Nehmen wir ein kurzes Beispiel:

Ich erstelle ein ViewModel namens vmA und eine Aktivität namens A und ich brauche die Daten des Benutzers. Ich werde das Repository in vmA des Benutzers einfügen.

Nun brauche ich eine weitere Aktivität, die Benutzerdaten lesen muss Ich erstelle ein anderes ViewModel mit dem Namen vmB, und darin werde ich das Benutzerrepository . Nennen.

Ein anderer bereits vorgeschlagener Weg besteht darin, mit der Implementierung der Factory N Instanzen desselben ViewModels zu erstellen.

0
AlexPad