Reaktive Programmierung von Kotlin mit RxJava und RxKotlin

Seit Kotlin eine offiziell unterstützte Sprache für die Android-Entwicklung geworden ist, erfreut sich Kotlin bei Android-Entwicklern großer Beliebtheit. Google verzeichnete einen Anstieg der Anwendungen, die mit Kotlin erstellt wurden.

Wenn Sie bereits RxJava oder RxAndroid verwendet haben und die Umstellung auf Kotlin durchführen möchten oder die reaktive Programmierung mit Kotlin starten möchten, ist dieses Tutorial für Sie. Wir werden die Grundlagen der Erstellung von RxJava 2.0 behandeln Beobachter, Observables und Datenströme in Kotlin, bevor Sie sich ansehen, wie Sie eine Tonne Boilerplate-Code aus Ihren Projekten schneiden können, indem Sie RxJava mit Kotlin-Erweiterungsfunktionen kombinieren.

Durch die Verwendung von RxJava mit Kotlin können Sie sehr reaktionsschnelle Apps in weniger Code erstellen. Eine Programmiersprache ist jedoch nicht perfekt. Deswegen werde ich auch eine Problemumgehung für das SAM-Konvertierungsproblem geben, das viele Entwickler beim ersten Einsatz von RxJava 2.0 mit Kotlin haben.

Zum Abschluss erstellen wir eine Anwendung, die zeigt, wie Sie RxJava verwenden können, um einige der Probleme zu lösen, die in echten Android-Projekten auftreten.

Wenn dies der erste Eindruck von RxJava ist, gebe ich Ihnen auf diesem Weg auch alle Hintergrundinformationen, die Sie benötigen, um die grundlegenden Konzepte von RxJava zu verstehen. Selbst wenn Sie noch nie mit RxJava experimentiert haben, haben Sie am Ende dieses Artikels ein solides Verständnis dafür, wie Sie diese Bibliothek in Ihren Projekten verwenden können, und Sie haben mehrere funktionierende Apps erstellt, die RxJava, RxKotlin, RxAndroid und RxBinding verwenden.

Was ist RxJava??

RxJava ist eine Open-Source-Implementierung der ReactiveX-Bibliothek, mit deren Hilfe Sie Anwendungen im reaktiven Programmierstil erstellen können. Obwohl RxJava für die Verarbeitung synchroner und asynchroner Datenströme ausgelegt ist, ist es nicht auf "herkömmliche" Datentypen beschränkt. RxJavas Definition von "Daten" ist ziemlich weit gefasst und umfasst Dinge wie Caches, Variablen, Eigenschaften und sogar Benutzereingabeereignisse wie Klicks und Wischbewegungen. Nur weil Ihre Anwendung keine großen Zahlen verarbeitet oder komplexe Datentransformationen durchführt, bedeutet das nicht, dass sie nicht von RxJava profitieren kann!

Weitere Informationen zur Verwendung von RxJava für Android-Apps finden Sie hier auf Envato Tuts+.

Wie funktioniert RxJava??

RxJava erweitert das Observer-Software-Designmuster, das auf dem Konzept von Observers und Observables basiert. Um eine grundlegende RxJava-Datenpipeline zu erstellen, müssen Sie:

  • Erstellen Sie ein Observable.
  • Geben Sie dem Observable einige Daten zum Aussenden.  
  • Erstellen Sie einen Observer.
  • Abonnieren Sie den Observer zum Observable.

Sobald das Observable über mindestens einen Observer verfügt, werden Daten gesendet. Jedes Mal, wenn das Observable eine Datenmenge ausgibt, benachrichtigt es den ihm zugewiesenen Observer durch Aufruf von onNext () und der Observer führt dann normalerweise eine Aktion in Reaktion auf diese Datenemission durch. Sobald das Observable mit dem Senden der Daten fertig ist, benachrichtigt es den Observer durch einen Anruf onComplete (). Das Observable wird dann beendet und der Datenstrom endet.

Wenn eine Ausnahme auftritt, dann onError () wird aufgerufen, und das Observable wird sofort beendet, ohne weitere Daten zu senden oder anzurufen onComplete ().

Aber RxJava ist es nicht gerade über die Weitergabe von Daten von einem Observable an einen Observer! RxJava verfügt über eine Vielzahl von Operatoren, mit denen Sie diese Daten filtern, zusammenführen und transformieren können. Stellen Sie sich zum Beispiel vor, Ihre App hat eine Zahl jetzt Taste, die erkennt onClick Sie sind besorgt, dass ein ungeduldiger Benutzer möglicherweise mehrmals auf die Schaltfläche tippt, was dazu führt, dass Ihre App mehrere Zahlungen verarbeitet.  

Mit RxJava können Sie diese verwandeln onClick Ereignisse in einen Datenstrom, den Sie mit den verschiedenen Operatoren von RxJava bearbeiten können. In diesem speziellen Beispiel können Sie die debounce () Betreiber, um Datenemissionen zu filtern, die in schneller Folge auftreten, also auch dann, wenn sich der Benutzer auf der Zahl jetzt Schaltfläche, Ihre App registriert immer nur eine einzelne Zahlung.

Welche Vorteile bietet RxJava??

Wir haben gesehen, wie RxJava Ihnen helfen kann, ein bestimmtes Problem in einer bestimmten Anwendung zu lösen, aber was hat es im Allgemeinen für Android-Projekte zu bieten??

Mit RxJava können Sie Ihren Code vereinfachen, indem Sie Ihnen eine Möglichkeit zum Schreiben des gewünschten Ergebnisses geben, anstatt eine Liste mit Anweisungen zu erstellen, die Ihre Anwendung durchlaufen muss. Wenn Sie beispielsweise alle Datenemissionen ignorieren möchten, die innerhalb eines Zeitraums von 500 Millisekunden stattfinden, schreiben Sie Folgendes:

.debounce (500, TimeUnit.MILLISECONDS)

Darüber hinaus seit RxJava behandelt beinahe alles Als Daten stellt es eine Vorlage bereit, die Sie auf eine Vielzahl von Ereignissen anwenden können: Erstellen Sie ein Observable, erstellen Sie einen Observer, abonnieren Sie den Observer für das Observable, spülen Sie und wiederholen Sie es. Dieser formelle Ansatz führt zu einem viel einfacheren, für Menschen lesbaren Code.

Der andere große Vorteil für Android-Entwickler besteht darin, dass RxJava das Multithreading unter Android erheblich lindern kann. Heutige mobile Benutzer erwarten, dass ihre Anwendungen Multitasking durchführen können, selbst wenn dies so einfach ist wie das Herunterladen von Daten im Hintergrund, während sie auf Eingaben des Benutzers reagieren.

Android verfügt über mehrere integrierte Lösungen zum Erstellen und Verwalten mehrerer Threads. Keine davon ist jedoch besonders einfach zu implementieren. Sie können schnell zu komplexem, ausführlichem Code führen, der schwer lesbar und fehleranfällig ist.

In RxJava erstellen und verwalten Sie zusätzliche Threads mithilfe einer Kombination von Operatoren und Schedulern. Sie können den Thread, in dem die Arbeit ausgeführt wird, einfach mit der Taste ändern subscribeOn Operator plus einen Scheduler. Zum Beispiel planen wir hier die Arbeit für einen neuen Thread:

.subscribeOn (Schedulers.newThread ())

Mit können Sie angeben, wo die Ergebnisse dieser Arbeit gebucht werden sollen beobachten Operator. Hier veröffentlichen wir die Ergebnisse in Androids wichtigstem Haupt-UI-Thread mit der AndroidSchedulers.mainThread Scheduler, der als Teil der RxAndroid-Bibliothek verfügbar ist:

.observOn (AndroidSchedulers.mainThread ())

Im Vergleich zu den integrierten Multithreading-Lösungen von Android ist der Ansatz von RxJava viel prägnanter und verständlicher.

In meinem Artikel Erste Schritte mit RxJava 2 für Android erfahren Sie mehr über die Funktionsweise von RxJava und die Vorteile, wenn Sie diese Bibliothek zu Ihrem Projekt hinzufügen.

Sollte ich RxJava oder RxKotlin verwenden??

Da Kotlin zu 100% mit Java kompatibel ist, können Sie die meisten Java-Bibliotheken in Ihren Kotlin-Projekten problemlos verwenden - und die RxJava-Bibliothek ist keine Ausnahme.

Dort ist eine dedizierte RxKotlin-Bibliothek, die einen Kotlin-Wrapper um die reguläre RxJava-Bibliothek darstellt. Dieser Wrapper bietet Erweiterungen, die RxJava für die Kotlin-Umgebung optimieren und die Menge an Boilerplate-Code, den Sie schreiben müssen, weiter reduzieren.

Da Sie RxJava in Kotlin verwenden können, ohne RxKotlin zu benötigen, wird in diesem Artikel RxJava verwendet, sofern nicht anders angegeben.

Einfache Beobachter und Observables in Kotlin erstellen

Observer und Observables sind die Bausteine ​​von RxJava. Beginnen wir mit der Erstellung von:

  • Ein einfaches Observable, das als Reaktion auf ein Schaltflächenklickereignis einen kurzen Datenstrom ausgibt.
  • Ein Observable, das auf diese Daten reagiert, indem verschiedene Meldungen an Android Studio gesendet werden Logcat.

Erstellen Sie ein neues Projekt mit den Einstellungen Ihrer Wahl, aber stellen Sie sicher, dass Sie das auswählen Kotlin-Unterstützung einschließen Kontrollkästchen, wenn Sie dazu aufgefordert werden. Als nächstes öffnen Sie Ihr Projekt build.gradle Datei und fügen Sie die RxJava-Bibliothek als Projektabhängigkeit hinzu:

Abhängigkeiten ImplementierungsdateiBaum (Verzeichnis: 'libs', include: ['* .jar']) Implementierung "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" Implementierung "androidx.appcompat: appcompat: 1.0.0- alpha1 'Implementierung' androidx.constraintlayout: constraintlayout: 1.1.0 'Implementierung' io.reactivex.rxjava2: rxjava: 2.1.9 '

Dann öffnen Sie Ihr Projekt activity_main.xml Datei und fügen Sie die Schaltfläche hinzu, die den Datenstrom startet:

  

Es gibt verschiedene Möglichkeiten, ein Observable zu erstellen, aber eine der einfachsten ist die Verwendung von gerade() Operator, um ein Objekt oder eine Liste von Objekten in ein Observable umzuwandeln.

Im folgenden Code erstellen wir ein Observable (myObservable) und geben Sie die Punkte 1, 2, 3, 4 und 5 zum Aussenden. Wir erstellen auch einen Observer (myObserver), abonniere es myObservable, und dann sagen Sie es, um eine Nachricht zu drucken Logcat jedes Mal erhält es eine neue Emission.

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import io.reactivex.Observable import io.reactivex.Observer import io.reactivex.disposables.Disposables import kotlinx.android.synthetic.main.activity_main . * class MainActivity: AppCompatActivity () private var TAG = "MainActivity" überschreibt fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Starten Sie den Stream, wenn Sie auf die Schaltfläche klicken // button.setOnClickListener startRStream () private fun startRStream () // Erzeuge ein Observable // val myObservable = getObservable () // Erzeuge einen Observer // val myObserver = getObserver () // myObserver bei myObservable abonnieren / / myObservable .subscribe (myObserver) privater Spaß getObserver (): Observer zurück Objekt: Beobachter override fun onSubscribe (d: Disposable)  // Bei jedem Aufruf von onNext wird der Wert in Logcat von Android Studio // gedruckt. // onNext (s: String) überschreiben. Log.d (TAG, "onNext: $ s")  // Wird aufgerufen, wenn eine Ausnahme ausgelöst wird // Fun onError überschreiben (e: Throwable) Log.e (TAG, "onError:" + e.message) // Wenn onComplete aufgerufen wird, geben Sie Folgendes an Logcat // aus. Überschreibe fun onComplete () Log.d (TAG, "onComplete") // // Gib myObservable einige Daten, um // private fun zu emittieren getObservable (): Observable return Observable.just ("1", "2", "3", "4", "5")

Sie können diese Anwendung nun testen:

  • Installieren Sie Ihr Projekt auf einem physischen Android-Smartphone oder -Tablet oder einem virtuellen Android-Gerät (AVD)..
  • Gib die Starten Sie den RxJava-Stream Knopf ein Klick.
  • Öffnen Sie den Logcat-Monitor von Android Studio, indem Sie die Option auswählen Android-Monitor Registerkarte (wo sich der Cursor im folgenden Screenshot befindet) und wählen Sie dann die Option aus Logcat Tab.

An diesem Punkt beginnt das Observable mit dem Senden seiner Daten und der Observer druckt seine Meldungen an Logcat. Ihre Logcat-Ausgabe sollte ungefähr so ​​aussehen:

Sie können dieses Projekt von GitHub herunterladen, wenn Sie es selbst ausprobieren möchten.

Kotlin-Erweiterungen für RxJava

Nun, da wir gesehen haben, wie Sie eine einfache RxJava-Pipeline in Kotlin einrichten, wollen wir uns ansehen, wie Sie dies erreichen können Weniger Code, mit den Erweiterungsfunktionen von RxKotlin.

Um die RxKotlin-Bibliothek zu verwenden, müssen Sie sie als Projektabhängigkeit hinzufügen:

Abhängigkeiten ImplementierungsdateiBaum (Verzeichnis: 'libs', include: ['* .jar']) Implementierung "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" Implementierung "androidx.appcompat: appcompat: 1.0.0- alpha1 'Implementierung' androidx.constraintlayout: constraintlayout: 1.1.0 'Implementierung' io.reactivex.rxjava2: rxjava: 2.1.9 '// Fügen Sie die folgende // Implementierung hinzu:' io.reactivex.rxjava2: rxkotlin: 2.2.0 '

Im folgenden Beispiel verwenden wir RxKotlin's toObservable () Erweiterungsfunktion, um a Liste in ein Observable. Wir benutzen auch die subscribeBy () Erweiterungsfunktion, da es uns ermöglicht, einen Observer mit benannten Argumenten zu erstellen, was zu klarerem Code führt.

import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.toObservable import kotlinx.android.synthetic.main.activity_main. * class MainActivityApp fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Starten Sie den Stream, wenn Sie auf die Schaltfläche klicken. // button.setOnClickListener startRStream () private fun startRStream ()  val list = listOf ("1", "2", "3", "4", "5") // Anwenden der toObservable () - Erweiterungsfunktion // list.toObservable () // Konstruieren Sie Ihren Observer mit subscribeBy ( ) Erweiterungsfunktion // .subscribeBy (onNext = println (it), onError = it.printStackTrace (), onComplete = println ("onComplete!"))

Hier ist die Ausgabe, die Sie sehen sollten:

Das Problem der SAM-Mehrdeutigkeit von RxJava lösen

RxKotlin bietet auch eine wichtige Problemumgehung für das SAM-Konvertierungsproblem, das auftreten kann, wenn mehrere SAM-Parameter in einer bestimmten Java-Methode überladen werden. Diese SAM-Mehrdeutigkeit verwirrt den Kotlin-Compiler, da er nicht herausfinden kann, welche Schnittstelle konvertiert werden soll, und das Projekt daher nicht kompiliert werden kann.

Diese SAM-Mehrdeutigkeit ist ein besonderes Problem bei der Verwendung von RxJava 2.0 mit Kotlin, da viele der RxJava-Operatoren mehrere SAM-kompatible Typen verwenden.

Sehen wir uns das SAM-Konvertierungsproblem in Aktion an. Im folgenden Code verwenden wir die Postleitzahl() Operator, um die Ausgabe von zwei Observables zu kombinieren:  

import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import io.reactivex.Observable import kotlinx.android.synthetic.main.activity_main. * class MainActivity: AppCompatActivity () override fun onCreate (savedInstanceState: Bundle?) hinzugefügt .onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Starten Sie den Stream, wenn Sie auf die Schaltfläche klicken. // button.setOnClickListener startRStream () privater Spaß startRStream () val numbers = Observable.range (1, 6 ) val strings = Observable.just ("Eins", "Zwei", "Drei", "Vier", "Fünf", "Sechs") Val gezippt = Observable.zip (Strings, Zahlen) s, n -> " $ s $ n " zipped.subscribe (:: println)

Dies bewirkt, dass der Kotlin-Compiler einen Typinferenzfehler ausgibt. RxKotlin bietet jedoch Hilfsmethoden und Erweiterungsfunktionen für die betroffenen Operatoren, einschließlich Observables.zip (), was wir im folgenden Code verwenden:

import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import io.reactivex.Observable import io.reactivex.rxkotlin.Observables import kotlinx.android.synthetic.main.activity_main. * Klasse Hauptaktivität: AppCompatActivity () (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Starten Sie den Stream, wenn Sie auf die Schaltfläche klicken. // button.setOnClickListener startRStream () private fun startRStream () val numbers = Observable.range (1, 6) val Zeichenfolgen = Observable.just ("Eins", "Zwei", "Drei", "Vier", "Fünf", "Sechs") val gezippt = Observables.zip (Strings, Zahlen ) s, n -> "$ s $ n" zipped.subscribe (:: println)

Hier ist die Ausgabe dieses Codes:

Fazit

In diesem Lernprogramm habe ich Ihnen gezeigt, wie Sie die RxJava-Bibliothek in Ihren Kotlin-Projekten verwenden können, einschließlich der Verwendung einer Reihe zusätzlicher unterstützender Bibliotheken wie RxKotlin und RxBinding. Wir haben untersucht, wie Sie in Kotlin einfache Observer und Observables erstellen können, bis Sie RxJava mit Erweiterungsfunktionen für die Kotlin-Plattform optimieren.

Bisher haben wir RxJava verwendet, um einfache Observables zu erstellen, die Daten ausgeben, und Observer, die diese Daten in Logcat von Android Studio drucken. Dies ist jedoch nicht die Art, wie Sie RxJava in der realen Welt verwenden!

Im nächsten Beitrag werden wir untersuchen, wie RxJava bei der Lösung von Problemen in der realen Welt helfen kann, die bei der Entwicklung von Android-Anwendungen auftreten. Wir werden RxJava mit Kotlin verwenden, um einen Klassiker zu erstellen Anmelden Bildschirm.