Umgang mit Such-API-Aufrufen bei Textänderungen
In diesem Artikel erfahren wir, wie wir die Suche in Android effizient implementieren können. Wenn Benutzer in Ihrer App nach etwas suchen, zeigen wir bei jeder Textänderung eine Liste mit Vorschlägen an, nach denen sie möglicherweise suchen.
Nehmen wir ein Beispiel:
Wenn wir in der Medium-App nach Personen suchen, sehen wir bei jeder Textänderung ein entsprechendes Ergebnis.
Der Code sieht in etwa so aus:
searchEditText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable) {
// api call to send search text , and get respective result
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})
Herausforderungen, denen wir dabei gegenüberstehen:
- Leistungsprobleme : Netzwerkaufrufe bei jedem Textänderungsereignis können zu Leistungsproblemen führen und die App verlangsamen.
- API-Ratenbegrenzung: Einige APIs verfügen über Richtlinien zur Ratenbegrenzung, die die Anzahl der Anfragen begrenzen können, die innerhalb eines bestimmten Zeitrahmens gestellt werden können. Häufige Aufrufe solcher APIs können dazu führen, dass das Ratenlimit erreicht wird, was dazu führen kann, dass die API weitere Anfragen ablehnt.
- Benutzererfahrung : API-Aufrufe bei jedem Textänderungsereignis können dazu führen, dass die Benutzeroberfläche nicht mehr reagiert, was zu einer schlechten Benutzererfahrung führt.
- Datengenauigkeit : Die von der API erhaltenen Ergebnisse sind möglicherweise nicht genau oder für die Suchanfrage des Benutzers relevant. Dies kann zu Frustration und Unzufriedenheit bei den Nutzern führen.
Es gibt verschiedene Möglichkeiten, dieses Problem anzugehen.
1. Reaktive Programmierung / Rx
RxTextView
RxTextView ist eine Komponente der Reactive Extensions (Rx)-Bibliothek, die speziell für Android-Entwickler entwickelt wurde. Es handelt sich um eine Erweiterung der RxJava-Bibliothek, die reaktive Bindungen zwischen Android TextView-Widgets und Observable-Streams bereitstellt.
Mit RxTextView können Sie ganz einfach Observables erstellen, die Änderungen an der Texteigenschaft von TextView-Widgets ausgeben, z. B. wenn der Text geändert wird, wenn er beim Klicken den Fokus erhält oder verliert und so weiter. Anschließend können Sie diese Observables verwenden, um reaktive Vorgänge wie Filterung, Zuordnung und Kombination der ausgegebenen Ereignisse durchzuführen.
RxTextView ist besonders nützlich, wenn Sie mit Benutzereingaben und UI-Updates arbeiten, da Sie damit reaktiven Code schreiben können, der in Echtzeit auf Änderungen der Benutzereingaben reagiert, ohne manuelle Ereignis-Listener oder Rückrufe verwenden zu müssen.
Das scheint also für unser Problem sehr nützlich zu sein. Mal sehen, wie wir es umsetzen.
Schritt 1: Abhängigkeit hinzufügen, sie ist Teil von Rxjava2
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
Disposable disposable = RxTextView.textChanges(textView)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<CharSequence>() {
@Override
public void accept(CharSequence charSequence) throws Exception {
// do something with the updated text
}
});
subscribeOn: Hier erfahren Sie, in welchem Thread Observable ausgeführt werden soll
subscribe : Es abonniert das Observable und stellt einen Consumer bereit, der jedes Mal aufgerufen wird, wenn sich der Text ändert. Im Consumer können Sie die Logik implementieren, die Sie mit dem aktualisierten Text ausführen möchten.
Vergessen Sie nicht, das Abonnement zu entsorgen, wenn es nicht mehr benötigt wird, um Speicherverluste zu vermeiden:
@Override
protected void onDestroy() {
super.onDestroy();
disposable.dispose();
}
val searchTextObservable = RxTextView.textChanges(searchBarView)
.skipInitialValue()
.debounce(300, TimeUnit.MILLISECONDS)
Jetzt können wir hier noch ein paar Dinge hinzufügen, um es so zu optimieren, throttleLatestdass die letzte Textänderung erst ausgegeben wird, nachdem eine bestimmte Verzögerung seit der vorherigen Ausgabe verstrichen ist. und distinctUntilChangeddie sicherstellen, dass nur unterschiedliche Textwerte von ausgegeben werden searchTextObservable. Dadurch werden unnötige API-Aufrufe vermieden, wenn der Benutzer denselben Text erneut eingibt.
val searchTextObservable = RxTextView.textChanges(omnibarTextInput)
.skipInitialValue()
.debounce(300, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.throttleLatest(500, TimeUnit.MILLISECONDS)
Beobachten wir es nun:
// Define an Observable for the text changes in the search bar
val searchTextObservable = RxTextView.textChanges(omnibarTextInput)
.skipInitialValue()
.debounce(300, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.throttleLatest(500, TimeUnit.MILLISECONDS)
searchTextObservable
.observeOn(Schedulers.io())
.flatMap { searchText ->
apiService.search(searchText.toString())
.subscribeOn(Schedulers.io())
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe { searchResults ->
// Handle the search results
}
2. Kotlin Flow
// Define a flow for the text changes in the search bar
val searchTextFlow = searchBarView.textChanges()
.skipInitialValue()
.debounce(300)
.map { it.toString() }
.distinctUntilChanged()
// Make an API call every time the text changes in the search bar
searchTextFlow
.flatMapLatest { searchText ->
flow { emit(apiService.search(searchText)) }
.flowOn(Dispatchers.IO)
}
.flowOn(Dispatchers.Main)
.collect { searchResults ->
// Handle the search results
}
Um diese Funktion nutzen zu können, müssen Sie Folgendes implementieren:
com.jakewharton.rxbinding4.widget.textChanges
Um dies zu erreichen, müssen Sie Ihrem Projekt die folgenden Abhängigkeiten hinzufügen:
dependencies {
// RxJava 3
implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
// RxAndroid 3
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
// RxBinding 4
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
// RxBinding 4 for widgets
implementation 'com.jakewharton.rxbinding4:rxbinding-widget:4.0.0'
}
- Das Ergebnis
Flow<String>wird dann an übergebenflatMapLatest(), das mithilfe der Funktion den Fluss der Suchanfragen in einen Fluss von Suchergebnissen umwandeltapiService.search().flatMapLatest()wird anstelle vonmap()„weil“ verwendet undapiService.search()gibt eine AnzahlFlowvon Suchergebnissen zurück undflatMapLatest()reduziert die verschachteltenFlows in einen einzigen Fluss von Suchergebnissen. - Schließlich
flowOn(Dispatchers.Main)wird verwendet, um zurück zumMainDispatcher zu wechseln, um die Suchergebnisse imcollect()Operator zu verarbeiten.collect()wird verwendet, um die Suchergebnisse zu empfangen und sie in der Benutzeroberfläche zu verarbeiten.
Abschluss
Wir sollten immer darauf achten, wie wir die uns zur Verfügung gestellten Ressourcen nutzen. Höhere Netzwerkvorgänge können zu einer Verlangsamung Ihrer App führen, was sich auf die Leistung Ihrer App auswirken kann.
Die Verwendung eines reaktiven Ansatzes zur Bearbeitung von Suchanfragen und API-Aufrufen hat mehrere Vorteile:
- Effizienter Einsatz von Ressourcen
- Reaktionsfähige Benutzeroberfläche
- Leichter zu überlegen
- Parallelität und Thread-Sicherheit
Wenn Sie Feedback oder Fragen haben, schreiben Sie mir bitte an [email protected] . Wir freuen uns sehr über Ihr Klatschen, um anderen dabei zu helfen, diesen Artikel zu finden .
Level-Up-Codierung
Vielen Dank, dass Sie Teil unserer Community sind! Bevor du gehst:
- Klatschen Sie für die Geschichte und folgen Sie dem Autor
- Weitere Inhalte finden Sie in der Level Up Coding-Publikation
- Kostenloser Programmier-Interviewkurs ⇒ Kurs ansehen
- Folgen Sie uns: Twitter | LinkedIn | Newsletter

![Was ist überhaupt eine verknüpfte Liste? [Teil 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































