Android LiveData – Wie kann dasselbe ViewModel für verschiedene Aktivitäten wiederverwendet werden?
Lesezeit: 5 Minuten
Benutzer1209216
Beispiel ViewModel:
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
}
Hauptaktivität:
mModel = ViewModelProviders.of(this).get(NameViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = textView::setText;
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this, nameObserver);
Ich möchte anrufen mModel.getCurrentName().setValue(anotherName); in der zweiten Aktivität und lassen Sie MainActivity Änderungen empfangen. Ist das möglich?
Die “richtige” Antwort lautet: “Wenn Sie Daten zwischen ihnen austauschen möchten, sollten es keine unterschiedlichen Aktivitäten sein, und Sie sollten stattdessen Fragmente austauschen”.
– EpicPandaForce
19. März 2018 um 14:34 Uhr
@EpicPandaForce vielleicht, aber so funktioniert weder die AndroidStudio Master/Detail-Vorlage noch die Android Architecture Blueprints
– Markieren
10. Juli 2018 um 6:09 Uhr
@Mark, das ist dann ein Fehler der Android Architecture Blueprints und der Vorlage.
– EpicPandaForce
25. Januar 2019 um 22:00 Uhr
Bitte lesen Sie dies unter http://stackoverflow.com/questions/56521969/…
– Levon Petrosjan
10. Juni 2019 um 16:12 Uhr
Said Masoumi
Wenn du anrufst ViewModelProviders.of(this)erstellen/behalten Sie tatsächlich eine ViewModelStore was gebunden ist thisalso haben unterschiedliche Aktivitäten unterschiedliche ViewModelStore und jede ViewModelStore erstellt eine andere Instanz von a ViewModel mit einer bestimmten Fabrik, also können Sie nicht die gleiche Instanz von a haben ViewModel an verschiedenen ViewModelStores.
Sie können dies jedoch erreichen, indem Sie eine einzelne Instanz einer benutzerdefinierten ViewModel-Factory übergeben, die als Singleton-Factory fungiert, sodass immer dieselbe Instanz von Ihnen übergeben wird ViewModel zwischen verschiedenen Aktivitäten.
Zum Beispiel:
public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {
NameViewModel t;
public SingletonNameViewModelFactory() {
// t = provideNameViewModelSomeHowUsingDependencyInjection
}
@Override
public NameViewModel create(Class<NameViewModel> modelClass) {
return t;
}
}
Was Sie also brauchen, ist zu machen SingletonNameViewModelFactory Singleton (z. B. mit Dagger) und verwenden Sie es wie folgt:
Bewahren ViewModels zwischen verschiedenen Bereichen ist ein Anti-Pattern. Es wird dringend empfohlen, Ihre Datenschichtobjekte beizubehalten (z. B. Ihre DataSource oder Ihr Repository zu einem Singleton zu machen) und Ihre Daten zwischen verschiedenen Bereichen (Aktivitäten) aufzubewahren.
Wenn Sie bereits Daten in einer Singleton-Datenschicht zwischenspeichern, was ist dann der Sinn von ViewModel?
– EpicPandaForce
19. März 2018 um 14:36 Uhr
@EpicPandaForce, ich meine, egal wie sich Ihre Datenschicht verhält, ViewModel müssen Sie irgendwie über Ihre Datenänderungen informieren. Das Zwischenspeichern Ihrer Datenschicht ist also eine Möglichkeit, Ihre Daten in verschiedenen Bereichen zu verwalten.
– Said Masoumi
19. März 2018 um 14:43 Uhr
Nun, ja, ich denke, Sie haben Recht, ich sollte das nicht versuchen. Aber was ist mit Fragment, ist es eine gute Praxis, untergeordnete Fragmente dazu zu bringen, dasselbe Ansichtsmodell zu beachten? Zum Beispiel ViewModelProviders.of(getActivity()).get(NameViewModel.class) Inneres Fragment.
Wie erreichen wir dies, wenn wir DaggerViewModelFactory verwenden?
– Morteza Rastgoo
17. August 2019 um 11:36 Uhr
TotoliciCristian
Wenn Sie das Ansichtsmodell mithilfe der ViewModelProviders abrufen, die Sie als Lebenszykluseigentümer der MainActivity übergeben, ergibt dies das Ansichtsmodell für diese Aktivität. In der zweiten Aktivität erhalten Sie eine andere Instanz dieses ViewModel, diesmal für Ihre zweite Aktivität. Das zweite Modell wird eine zweite Live-Daten haben.
Was Sie tun können, ist, die Daten in einer anderen Ebene zu verwalten, z. B. einem Repository, das ein Singleton sein kann, und auf diese Weise können Sie dasselbe Ansichtsmodell verwenden.
public class NameViewModel extends ViewModel {
// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = DataRepository.getInstance().getCurrentName();
}
return mCurrentName;
}
}
//SingleTon
public class DataRepository
private MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<>();
}
return mCurrentName;
}
//Singleton code
...
}
Dies sollte eine akzeptierte Antwort sein … ohne das Android-Architekturmuster zu verletzen
– sum20156
29. Dezember 2020 um 13:40 Uhr
Auch diese Vorgehensweise wird empfohlen hier in diesem offiziellen Tutorial: LiveData in repositories: To avoid leaking ViewModels and callback hell, repositories can be observed
– Alierdogan7
17. Juni 2021 um 9:43 Uhr
Erstellen Sie einfach die Instanz Ihrer ViewModelin diesem Fall NameViewModel
Ihre ViewModel Factory mag sein
class ViewModelFactory : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>) =
with(modelClass){
when {
isAssignableFrom(NameViewModel::class.java) -> NameViewModel.getInstance()
else -> throw IllegalArgumentException("Unknown viewModel class $modelClass")
}
} as T
companion object {
private var instance : ViewModelFactory? = null
fun getInstance() =
instance ?: synchronized(ViewModelFactory::class.java){
instance ?: ViewModelFactory().also { instance = it }
}
}
}
Und Ihr ViewModel
class NameViewModel : ViewModel() {
//your liveData objects and many more...
companion object {
private var instance : NameViewModel? = null
fun getInstance() =
instance ?: synchronized(NameViewModel::class.java){
instance ?: NameViewModel().also { instance = it }
}
}
}
Jetzt können Sie verwenden ViewModelProviders um dieselbe Instanz Ihres ViewModel zur Verwendung in jeder Aktivität zu erhalten
Erstellen Sie eine Erweiterungsfunktion für einen einfacheren Zugriff
fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)
Ich habe diese Lösung ausprobiert, aber es funktioniert nicht. Versuch, eine TextView in einem Fragment aus einer zweiten Aktivität zu aktualisieren.
– Samuel
23. Januar 2020 um 20:49 Uhr
Können Sie sich meine Einreichung ansehen: stackoverflow.com/questions/59887014/…
– Samuel
23. Januar 2020 um 21:06 Uhr
Darrell Burk
ViewModel-Bereich/-Lebenszyklus ist an eine Aktivität gebunden, einfach weil der ViewModelStoreOwner, den Sie an den ViewModelProvider-Konstruktor übergeben, zufällig die Aktivität ist.
Da Sie den ViewModelStoreOwner bereitstellen können, können Sie genauso einfach einen bereitstellen, der einen längeren Lebenszyklus hat, z. B. die Anwendung.
Du kannst
Stellen Sie Ihre eigene Unterklasse von Application bereit und implementieren Sie ViewModelStoreOwner (und haben Sie einen ViewModelStore).
Übergeben Sie in ViewModelProvider-Konstruktoraufrufen activity.application anstelle von activity.
Dadurch interagiert der ViewModelProvider mit dem ViewModelStore auf Anwendungsebene, sodass Sie ViewModel-Instanzen mit Anwendungsbereich erstellen können.
14316800cookie-checkAndroid LiveData – Wie kann dasselbe ViewModel für verschiedene Aktivitäten wiederverwendet werden?yes
Die “richtige” Antwort lautet: “Wenn Sie Daten zwischen ihnen austauschen möchten, sollten es keine unterschiedlichen Aktivitäten sein, und Sie sollten stattdessen Fragmente austauschen”.
– EpicPandaForce
19. März 2018 um 14:34 Uhr
@EpicPandaForce vielleicht, aber so funktioniert weder die AndroidStudio Master/Detail-Vorlage noch die Android Architecture Blueprints
– Markieren
10. Juli 2018 um 6:09 Uhr
@Mark, das ist dann ein Fehler der Android Architecture Blueprints und der Vorlage.
– EpicPandaForce
25. Januar 2019 um 22:00 Uhr
Bitte lesen Sie dies unter http://stackoverflow.com/questions/56521969/…
– Levon Petrosjan
10. Juni 2019 um 16:12 Uhr