Gemäß Dokumentation
Transformations.map ()
Wendet eine Funktion auf den im LiveData-Objekt gespeicherten Wert an und gibt das Ergebnis nachgelagert weiter.
Transformations.switchMap ()
Wendet ähnlich wie map eine Funktion auf den im LiveData-Objekt gespeicherten Wert an und packt das Ergebnis stromabwärts aus und versendet es. Die an switchMap () übergebene Funktion muss ein LiveData-Objekt zurückgeben .
Mit anderen Worten, ich bin möglicherweise nicht 100% korrekt, aber wenn Sie mit RxJava vertraut sind; Transformations#map
ist ähnlich wie Observable#map
& Transformations#switchMap
ist ähnlich wie Observable#flatMap
.
Nehmen wir ein Beispiel, es gibt eine LiveData, die eine Zeichenfolge ausgibt, und wir möchten diese Zeichenfolge in Großbuchstaben anzeigen.
Ein Ansatz wäre wie folgt; in einer Aktivität oder einem Fragment
Transformations.map(stringsLiveData, String::toUpperCase)
.observe(this, textView::setText);
Die an übergebene Funktion map
gibt nur einen String zurück, aber Transformation#map
letztendlich gibt sie einen zurück LiveData
.
Der zweite Ansatz; in einer Aktivität oder einem Fragment
Transformations.switchMap(stringsLiveData, this::getUpperCaseStringLiveData)
.observe(this, textView::setText);
private LiveData<String> getUpperCaseStringLiveData(String str) {
MutableLiveData<String> liveData = new MutableLiveData<>();
liveData.setValue(str.toUpperCase());
return liveData;
}
Wenn Sie sehen, Transformations#switchMap
hat das tatsächlich gewechselt LiveData
. Also noch einmal gemäß Dokumentation. Die an switchMap () übergebene Funktion muss ein LiveData-Objekt zurückgeben .
Also, bei map
es ist die Quelle LiveData
Sie wandeln und bei switchMap
der übergebene LiveData
als handeln Auslöser , auf dem es zu einem anderen wechseln wird LiveData
nach auspacken und den Versand des Ergebnisses downstream.
Meine Beobachtung ist, dass Sie sich für die Verwendung entscheiden können, wenn Ihr Transformationsprozess schnell ist (ohne Datenbankbetrieb oder Netzwerkaktivität)
map
.Wenn Ihr Transformationsprozess jedoch langsam ist (einschließlich Datenbankbetrieb oder Netzwerkaktivität), müssen Sie verwenden
switchMap
switchMap
wird bei zeitaufwändigen Operationen verwendetclass MyViewModel extends ViewModel { final MutableLiveData<String> mString = new MutableLiveData<>(); final LiveData<Integer> mCode; public MyViewModel(String string) { mCode = Transformations.switchMap(mString, input -> { final MutableLiveData<Integer> result = new MutableLiveData<>(); new Thread(new Runnable() { @Override public void run() { // Pretend we are busy try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } int code = 0; for (int i=0; i<input.length(); i++) { code = code + (int)input.charAt(i); } result.postValue(code); } }).start(); return result; }); if (string != null) { mString.setValue(string); } } public LiveData<Integer> getCode() { return mCode; } public void search(String string) { mString.setValue(string); } }
map
ist nicht für zeitaufwändigen Betrieb geeignetclass MyViewModel extends ViewModel { final MutableLiveData<String> mString = new MutableLiveData<>(); final LiveData<Integer> mCode; public MyViewModel(String string) { mCode = Transformations.map(mString, input -> { /* Note: You can't launch a Thread, or sleep right here. If you do so, the APP will crash with ANR. */ /* try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } */ int code = 0; for (int i=0; i<input.length(); i++) { code = code + (int)input.charAt(i); } return code; }); if (string != null) { mString.setValue(string); } } public LiveData<Integer> getCode() { return mCode; } public void search(String string) { mString.setValue(string); } }
quelle
Zu allererst
map()
undswitchMap()
Methoden sowohl auf dem Haupt - Thread aufgerufen wird . Und sie haben nichts damit zu tun, für schnelle oder langsame Aufgaben verwendet zu werden. Es kann jedoch zu Verzögerungen auf der Benutzeroberfläche kommen, wenn Sie komplexe rechnerische oder zeitaufwändige Aufgaben innerhalb dieser Methoden anstelle eines Arbeitsthreads ausführen und beispielsweise eine lange und / oder komplexe JSON-Antwort analysieren oder konvertieren, da diese auf dem UI-Thread ausgeführt werden.Der Code der map () -Methode lautet
@MainThread public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, Y> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { @Override public void onChanged(@Nullable X x) { result.setValue(func.apply(x)); } }); return result; }
Es verwendet eine Quell-LiveData, I ist der Eingabetyp und ruft setValue (O) für LiveData auf, wobei O der Ausgabetyp ist.
Damit es klar ist, möchte ich ein Beispiel geben. Sie möchten den Benutzernamen und den Nachnamen in textView schreiben, wenn sich ein Benutzer ändert.
/** * Changes on this user LiveData triggers function that sets mUserNameLiveData String value */ private MutableLiveData<User> mUserLiveData = new MutableLiveData<>(); /** * This LiveData contains the data(String for this example) to be observed. */ public final LiveData<String> mUserNameLiveData;
Lassen Sie uns jetzt Änderungen an der Zeichenfolge von mUserNameLiveData auslösen, wenn sich mUserLiveData ändert.
/* * map() method emits a value in type of destination data(String in this example) when the source LiveData is changed. In this example * when a new User value is set to LiveData it trigger this function that returns a String type * * Input, Output * new Function<User, String> * * public String apply(User input) { return output;} */ // Result<Output> Source<Input> Input, Output mUserNameLiveData = Transformations.map(mUserLiveData, new Function<User, String>() { @Override public String apply(User input) { // Output return input.getFirstName() + ", " + input.getLastName(); } });
Und machen wir dasselbe mit
MediatorLiveData
/** * MediatorLiveData is what {@link Transformations#map(LiveData, Function)} does behind the scenes */ public MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>(); /* * map() function is actually does this */ mediatorLiveData.addSource(mUserLiveData, new Observer<User>() { @Override public void onChanged(@Nullable User user) { mediatorLiveData.setValue(user.getFirstName() + ", " + user.getLastName()); } });
Und wenn Sie MediatorLiveData bei Aktivität oder Fragment beobachten, erhalten Sie das gleiche Ergebnis wie beim Beobachten
LiveData<String> mUserNameLiveData
userViewModel.mediatorLiveData.observe(this, new Observer<String>() { @Override public void onChanged(@Nullable String s) { TextView textView = findViewById(R.id.textView2); textView.setText("User: " + s); Toast.makeText(MainActivity.this, "User: " + s, Toast.LENGTH_SHORT).show(); } });
switchMap () gibt bei jeder Änderung von SourceLiveData die gleichen MediatorLiveData zurück, keine neuen LiveData.
Es ist Quellcode ist
@MainThread public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger, @NonNull final Function<X, LiveData<Y>> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(trigger, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = func.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
Grundsätzlich wird eine endgültige MediatorLiveData erstellt und wie map () auf das Ergebnis gesetzt, aber diese Zeitfunktion gibt LiveData zurück
public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source, @NonNull final Function<X, **Y**> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { @Override public void onChanged(@Nullable X x) { result.setValue(func.apply(x)); } }); return result; } @MainThread public static <X, Y> LiveData<Y> switchMap(@NonNull LiveData<X> trigger, @NonNull final Function<X, **LiveData<Y>**> func) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(trigger, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = func.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; }
Also
map()
nimmtLiveData<User>
und transformiert es in einString
, wenn sich dasUser
Objekt ändert, ändert sich beispielsweise das Namensfeld.switchMap()
nimmt einen String undLiveData<User>
benutzt ihn. Fragen Sie einen Benutzer aus dem Web oder der Datenbank mit einem String ab und erhalten Sie einenLiveData<User>
als Ergebnis.quelle
Map () ist konzeptionell identisch mit der Verwendung in RXJava. Grundsätzlich ändern Sie einen Parameter von LiveData in einem anderen
SwitchMap () stattdessen ersetzen Sie die LiveData selbst durch eine andere! Ein typischer Fall ist, wenn Sie beispielsweise einige Daten aus einem Repository abrufen und die vorherigen LiveData "entfernen" (um den Speicher zu sammeln, um den Speicher normalerweise effizienter zu gestalten), übergeben Sie eine neue LiveData, die dieselbe Aktion ausführt (eine Abfrage für Beispiel)
quelle
Es gibt oben bereits einige gute Antworten, aber ich habe immer noch mit ihnen gekämpft, bis ich sie verstanden habe. Deshalb werde ich versuchen, ein konkretes Beispiel für Menschen mit meiner Denkweise zu erklären, ohne auf technische Details und Code einzugehen.
In den beiden
map
undswitchMap
es gibt eine Quelle (oder Trigger) Live - Daten, und in beiden Fällen Sie wollen verwandeln es in ein anderes Live - Daten . Welches Sie verwenden werden, hängt von der Aufgabe ab, die Ihre Transformation ausführt.map
Stellen Sie sich dasselbe einfache Beispiel vor, das überall verwendet wird - Ihre Quell- Live-Daten enthalten ein
User
Objekt -LiveData<User>
, das auf den aktuell angemeldeten Benutzer verweist. Sie möchten einen Text in Ihrer Benutzeroberfläche anzeigenCurrent user: <USERNAME>
. In diesem Fall sollte jedes Änderungssignal von der Quelle genau ein Signal der resultierenden "abgebildeten" auslösenLiveData
. Das aktuelleUser
Objekt ist beispielsweise "Bob", dann wird der UI-Text angezeigtCurrent user: Bob
. Sobald SieLiveData<User>
eine Änderung auslösen, wird Ihre Benutzeroberfläche diese beobachten und den Text auf aktualisierenCurrent user: Alice
. Sehr einfach, linear, eins zu eins ändern.switchMap
Betrachten Sie das folgende Beispiel: Sie möchten eine Benutzeroberfläche erstellen, in der die Benutzer angezeigt werden, deren Name mit dem angegebenen Suchbegriff übereinstimmt. Wir können ziemlich schlau sein und den Suchbegriff als LiveData halten! Es wird also ein
LiveData<String>
und jedes Mal, wenn der Benutzer eine neue Abfragezeichenfolge eingibt, setzt unserFragment
/Activity
einfach den Texteingabewert auf diese Live-Daten in derViewModel
. Infolgedessen lösen diese Live-Daten ein Änderungssignal aus. Sobald wir dieses Signal erhalten, suchen wir nach den Benutzern. Nehmen wir nun an, unsere Suche ist so schnell, dass sofort ein Wert zurückgegeben wird. An diesem Punkt denken Sie, dass Sie nur eine verwenden könnenmap
und geben Sie die übereinstimmenden Benutzer zurück, die die Benutzeroberfläche aktualisieren. Nun, Sie werden jetzt einen Fehler haben - stellen Sie sich vor, Sie aktualisieren die Datenbank regelmäßig und nach dem nächsten Update werden mehr Benutzer angezeigt, die dem Suchbegriff entsprechen! Wie Sie sehen, führt der Quellauslöser (Suchbegriff) in diesem Szenario nicht unbedingt zu einem einzigen Auslöser für zugeordnete Live-Daten. Die der Benutzeroberfläche zugewiesenen zugeordneten Live-Daten müssen möglicherweise weiterhin die Werte auslösen, nachdem neue Benutzer hinzugefügt wurden die Datenbank. An dieser Stelle könnte man sagen, dass wir "intelligentere" Live-Daten zurückgeben könnten, die nicht nur auf Quellauslöser warten, sondern auch die Datenbank auf Benutzer überwachen, die dem angegebenen Begriff entsprechen (dies können Sie mitRoom
DB out tun der Box). Aber dann kommt eine andere Frage - was ist, wenn sich der Suchbegriff ändert? Ihre Amtszeit war alsox
Es wurden Live-Daten ausgelöst, die die Benutzer abfragen und die Datenbank im Auge behalten. Sie werden zurückgegebenuserx, userxx
und nach fünf Minuten zurückgegebenuserx, userxxx
und so weiter. Dann wurde der Begriff in geänderty
. Jetzt müssen wir irgendwie Anschlag auf die Smart - Live - Daten hören uns Benutzer geben mitx
drin, und schalten Sie es mit den neuen Smart - Live - Daten , die überwacht und geben uns Benutzer mity
in ihren Namen. Und genau dasswitchMap
macht es! Und Hinweis, diese Schalter werden muss , um in einer solchen Art und Weise durchgeführt, dass in Ihrer Benutzeroberfläche Sie schreiben Sie einfachswitchMap(...).observe
einmal, dass Mittel , dieswitchMap
einen Wrapper zurückgeben muss ,LiveData
die die gleiche während der Ausführung bleiben, sondern schaltet die Live - Datenquellen unter der Haube für uns.Fazit
Obwohl sie auf den ersten Blick gleich aussehen, die Anwendungsfälle für
map
undswitchMap
unterschiedlich sind, werden Sie das Gefühl bekommen, welche Sie verwenden sollen, sobald Sie mit der Implementierung Ihres Falls beginnen, meistens wenn Sie feststellen, dass Sie in Ihrer Mapping-Funktion einige aufrufen müssen Code von Ihren anderen Modulen (wieRepositories
), die zurückkehrenLiveData
.quelle
val searcResultLiveData = database.getFirstUserMatching("alice")
und hören sich die Änderungen der Suchergebnisse für "Alice" an. Dann müssen Sie es der Zeichenfolge "Gefunden: <Benutzername>" zuordnen. Ihre Zuordnung wird nicht funktionieren , da Sie nennenmap
auf ,searcResultLiveData
aber sobald Sie den Suchbegriff Ihr Suchergebnis ändern müssen , Live - Daten geändert werden, werden Sie auch die abgebildeten Live - Daten zu aktualisieren.X
- nennen wir esval liveX: LiveData<X>
. Und dann müssen Sie ein Live-Datenobjekt behalten,Y
das abhängt vonX
:val liveY: LiveData<Y>
. Es ist logisch, eine Karte zu implementieren :val liveY = liveX.map {...}
. Dann beginnen Sie mit der Codierung der Mapping-Funktion in{...}
und bam! Sie erkennen, dass Sie in Ihrer Zuordnungsfunktion eine Drittanbieterfunktion (wie einen DB-Aufruf) aufrufen MÜSSEN, die Live-Daten zurückgibt! Dann haben Sie keine andere Wahl , als zu verwenden ,switchMap
stattmap
.map
Ihnen haben gleiche Quelle live am Ende , aber es ist Daten (Wert) ändert sich mit der vorgesehenen Funktion vor EmittierenswitchMap
Sie Quell-Livedata nur als Auslöser für die Rückgabe einer eigenständigen Livedata (natürlich können Sie Trigger-Daten in Ihrer Funktionseingabe verwenden).onChanged()
anruftquelle
switchMap: Nehmen wir an, wir suchen nach dem Benutzernamen Alice. Das Repository erstellt eine neue Instanz dieser User LiveData-Klasse und danach werden die Benutzer angezeigt. Nach einiger Zeit müssen wir nach dem Benutzernamen Bob suchen, da das Repository eine neue Instanz von LiveData erstellt und unsere Benutzeroberfläche diese LiveData abonniert. In diesem Moment abonniert unsere Benutzeroberfläche zwei Instanzen von LiveData, da wir die vorherige nie entfernen. Dies bedeutet, dass unser Repository bei jeder Änderung der Benutzerdaten ein zweimaliges Abonnement sendet. Wie lösen wir dieses Problem?
Was wir tatsächlich brauchen, ist ein Mechanismus, mit dem wir aufhören können, von der vorherigen Quelle aus zu beobachten, wann immer wir eine neue beobachten wollen. Dazu würden wir switchMap verwenden. Unter der Haube verwendet switchMap MediatorLiveData, mit dem die ursprüngliche Quelle entfernt wird, wenn die neue Quelle hinzugefügt wird. Kurz gesagt, es übernimmt den gesamten Mechanismus zum Entfernen und Hinzufügen eines neuen Beobachters für uns.
Die Karte ist jedoch statisch und wird verwendet, wenn Sie nicht jedes Mal neue Live-Daten abrufen müssen
quelle
Kurz gesagt, die Benennung ist analog zu rx map / switchMap.
Die Zuordnung ist eine 1: 1-Zuordnung, die leicht zu verstehen ist.
SwitchMap hingegen ordnet jeweils nur den aktuellsten Wert zu, um unnötige Berechnungen zu reduzieren.
Hoffe, diese kurze Version der Antwort kann das Problem aller leicht lösen.
quelle
Transformation.map ()
fun <X, Y> map(trigger: LiveData<X>, mapFunction: Function<X, Y> ): LiveData<Y>?
trigger
- Die LiveData-Variable, die einmal geändert wurde, löstmapFunction
die Ausführung aus.mapFunction
- Die Funktion, die aufgerufen werden soll, wenn eine Änderung an dentrigger
LiveData vorgenommen wird. Parameter X ist eine Referenz auftrigger
(viait
). Die Funktion gibt ein Ergebnis des angegebenen Typs Y zurück, das letztendlichmap()
als LiveData-Objekt zurückgegeben wird.Verwenden
map()
Sie diese Option, wenn Sie eine Operation (übermapFunction
) ausführen möchten, wenn sich dietrigger
LiveData-Variable ändert.map()
gibt ein LiveData-Objekt zurück, das beim Aufruf beachtet werdenmapFunction
sollte.Beispiel:
Nehmen Sie eine einfache Liste von Bowlernamen an, deren Durchschnitt und Durchschnitt mit Handicap:
data class Bowler(val name:String, val average:Int, var avgWHDCP:Int) var bowlers = listOf<Bowler>(Bowler("Steve", 150,150), Bowler ("Tom", 210, 210))
Angenommen, eine
MutableLiveData
Int
Variable enthält einen Handicap-Inkrementwert. Wenn sich dieser Wert ändert, müssenavgWHDCP
alle Bowler in der Liste neu berechnet werden. Anfangs wird es auf Null gesetzt.var newHDCP:MutableLiveData<Int> = MutableLiveData(0)
Erstellen Sie eine Variable, die aufruft
Tranformation.map()
. Das erste Argument istnewHDCP
. Das zweite Argument ist die Funktion, die beinewHDCP
Änderungen aufgerufen werden soll . In diesem Beispiel durchläuft die Funktion alle Bowlerobjekte, berechnet die neueavgWHDCP
für jeden Bowler in der Bowlerliste und gibt das Ergebnis als beobachtbare Liste von LiveData Bowler-Objekten zurück. Beachten Sie, dass in diesem Beispiel die ursprüngliche Nicht-LiveData-Liste der Bowler und die zurückgegebene Liste der Bowler denselben Wert widerspiegeln, da sie auf denselben Datenspeicher verweisen. Das Ergebnis der Funktion ist jedoch beobachtbar. Die ursprüngliche Liste der Bowler ist nicht so, wie sie nicht als LiveData eingerichtet wurde.var updatedBowlers: LiveData<List<Bowler>> = Transformations.map(newHDCP) { bowlers.forEach { bowler -> bowler.avgWHDCP = bowler.average + it } return@map bowlers }
Fügen Sie irgendwo in Ihrem Code eine Methode zum Aktualisieren hinzu
newHDCP
. In meinem Beispiel wird beim Klicken auf ein OptionsfeldnewHDCP
etwas geändert, und der Prozess wird ausgelöst, um die in angegebene Funktion aufzurufenTransformations.map()
rbUpdateBy20.setOnCheckedChangeListener { _, isChecked -> viewModel.bowlingBallObject.newHDCP.value = 20 }
Schließlich funktioniert dies alles nur, wenn
updatedBowlers
es beachtet wird. Dies würde in Ihrer Aktivität oder Fragment in einer Methode wie platziertOnViewCreated()
viewModel.updatedBowlers.observe(viewLifecycleOwner, Observer { bowler -> if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) { refreshRecycler() } })
Wenn Sie etwas prägnanter werden möchten und wirklich keinen Live-Verweis benötigen
updatedBowlers
, können Sie FolgendesupdateBowlers
mit dem Beobachter kombinieren :Transformations.map(viewModel.newHDCP) { viewModel.bowlers.forEach { bowler -> bowler.avgWHDCP = bowler.average + it } return@map viewModel.bowlers }.observe(viewLifecycleOwner, Observer { bowler -> if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) { refreshRecycler() } })
Und das war's auch schon. Jedes Mal, wenn Sie den Wert von ändern
newHDCP
, wird die in angegebene FunktionTransformation.map()
aufgerufen, das Bowler-Objekt mit dem neu berechneten transformiertavgWHDCP
und ein LiveData-Objekt von zurückgegebenList<Bowler>
Transformation.switchMap ()
fun <X, Y> switchMap(source: LiveData<X>, switchMapFunction: Function<X, LiveData<Y>!>): LiveData<Y>
source
- Die LiveData-Variable, die nach dem Ändern dieswitchMapFunction
Ausführung auslöst .switchMapFunction
- Die Funktion, die aufgerufen werden soll, wenn eine Änderung an den LiveData-Quellen vorgenommen wird. Parameter X bezieht sich auf dasselbe Quellobjekt (viait
). DieswitchMapFunction
Funktion MUSS ein LiveData-Ergebnis zurückgeben, das effektiv über zurückgegeben wirdTransformation.switchMap()
. Im Wesentlichen können Sie so eine Referenz eines LiveData-Containerobjekts gegen eine andere austauschen.Verwenden
switchMap()
Sie diese Option, wenn Sie eine Variable haben, die auf ein LiveData-Objekt verweist, und diese Variable auf eine andere umschalten oder auf andere Weise den vorhandenen LiveData-Container aktualisieren möchten. Dies ist beispielsweise nützlich, wenn Ihre LiveData-Variable auf einen Datenbankdatenspeicher verweist und Sie eine Anforderung mit verschiedenen Parametern durchführen möchten.switchMap
Mit dieser Option können Sie die Abfrage erneut ausführen und durch neue LiveData-Ergebnisse ersetzen.Beispiel :
Angenommen, ein Datenbank-Repository mit einer Reihe von Bowlingkugel-Abfragen aus einer BowlingBall-DAO-Tabelle:
private val repository = BowlingBallRepository(application)
Und ich möchte eine Abfrage ausführen, die aktive oder inaktive Bowlingkugeln abruft, je nachdem, was der Benutzer angibt. Über die Benutzeroberfläche kann der Benutzer aktiv oder inaktiv auswählen, sodass meine Abfrage beide verarbeiten muss. Also erstelle ich eine
MutableLiveData
Variable, die einen aktiven oder inaktiven Status hat. In diesem Beispiel ist standardmäßig 'A' für aktiv.var activeFlag:MutableLiveData<String> = MutableLiveData(“A”)
Jetzt benötigen wir eine LiveData-Variable, die das Ergebnis meiner Abfrage enthält, um alle Bowlingkugeln eines bestimmten Status abzurufen. Also erstelle ich eine Variable namens
allBowlingBalls
typeLiveData<List<BowlingBallTable>>?
und weise sie zuTransformation.switchMap
. Ich übergebe derswitchMap
Funktion dieactiveFlag
Variable sowie eine Lambda-Funktion, die dieselbeactiveFlag
Variable (viait
) empfängt, und die Funktion ruft eine Abfrage im DB-Repository auf, um alle Bowlingkugeln mit dem übergebenen Status erneut abzurufen. Das LiveData-Ergebnis der Lambda-Funktion durchläuft dieswitchMap
Methode und wird neu zugewiesenallBowlingBalls
.private var allBowlingBalls: LiveData<List<BowlingBallTable>>? = Transformations.switchMap(activeFlag) {repository.getAllBalls(it)}
Ich brauche einen Weg, um eine Aktualisierung von auszulösen
allBowlibgBalls
. Dies wird wiederum beiactiveFlag
Änderungen durchgeführt. Fügen Sie irgendwo in Ihrem Code eine zu aktualisierende Funktion hinzuactiveFlag
. In meinem Beispiel wird beim Klicken auf ein OptionsfeldactiveFlag
etwas geändert, und der Prozess wird ausgelöst, um die in angegebene Funktion aufzurufenTransformations.switchMap()
rbActive.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { viewModel.activeFlag.value = ActiveInactive.ACTIVE.flag refreshRecycler() } }
Schließlich funktioniert dies alles nur, wenn allBowlingBalls beobachtet wird. Erstellen Sie also zuerst eine Funktion zum Abrufen von allBowlingBalls:
fun getAllBowlingBalls():LiveData<List<BowlingBallTable>>? { return allBowlingBalls }
Dann setzen Sie einen Beobachter auf
getAllBowlingBalls()
:viewModel.getAllBowlingBalls()?.observe(viewLifecycleOwner, Observer { balls -> if (viewLifecycleOwner.lifecycle.currentState == Lifecycle.State.RESUMED) { refreshRecycler() } })
Und das war's. Jedes Mal
activeFlag
, wenn sich Änderungen ergeben,allBowlingBalls
wird es mit einem Aufruf des Repositorys aktualisiert und dasonChange
Ereignis des BeobachtersallBowlingBalls
wird ausgelöst. Eine einfache Technik zum Aufbau einer dynamischen Suchmaschine.quelle
Lassen Sie mich anhand eines Beispiels erklären, was ich verstanden habe. Betrachten Sie eine Schülerdatenklasse
data class Student(val name: String, val marks: Int)
Transformation.map ()
Wandelt den Wert von LiveData in einen anderen um. Es nimmt den Wert, wendet die Funktion auf den Wert an und legt die Ausgabe der Funktion als Wert für die zurückgegebenen LiveData fest. Hier ist ein Beispiel, wie dies für die obige Datenklasse verwendet werden kann:
val student: LiveData<Student> = (get liveData<Student> from DB or network call) val studentName: LiveData<String> = Transformations.map(student) {it.name}
Hier erhalten wir LiveData eines Schülers aus einem Netzwerk oder einer Datenbank. Anschließend nehmen wir den Wert aus LiveData, das das Student-Objekt ist, und rufen einfach den Namen des Schülers ab und ordnen ihn einem anderen LiveData zu.
Transformation.switchMap ()
Wandelt den Wert einer LiveData in eine andere LiveData um. Stellen Sie sich vor, wir möchten eine Suchfunktion für Schüler implementieren. Jedes Mal, wenn sich der Suchtext ändert, möchten wir die Suchergebnisse aktualisieren. Der folgende Code zeigt, wie das funktioniert.
val searchQuery: LiveData<String> = ... val searchResults: LiveData<List<Student>> = Transformations.switchMap(searchQuery) { getSearchResults(it) } fun getSearchResults(query: String): LiveData<List<Student>> = (get liveData<List<Student>> from DB or network call)
Jedes Mal, wenn in searchQuery ein neuer Wert vorhanden ist, wird getSearchResults mit einer neuen Suchabfrage aufgerufen und searchResults wird aktualisiert.
quelle