Kotlin Reactive Programmering Med RxJava og RxKotlin

Siden blitt et offisielt støttet språk for Android-utvikling, har Kotlin raskt vokst i popularitet blant Android-utviklere, med Google rapporterer en 6x økning i programmene som er opprettet ved hjelp av Kotlin.

Hvis du tidligere har brukt RxJava eller RxAndroid og ønsker å bytte til Kotlin, eller ønsker å starte reaktiv programmering med Kotlin, er denne opplæringen for deg. Vi vil dekke grunnleggende om å opprette RxJava 2.0 observatører, observer og datastrømmer i Kotlin, før du ser på hvordan du kan trimme et ton boilerplate-kode fra prosjektene dine, ved å kombinere RxJava med Kotlin-utvidelsesfunksjoner.

Bruke RxJava med Kotlin kan hjelpe deg med å lage svært reaktive programmer i mindre kode, men ingen programmeringsspråk er perfekt, så jeg vil også dele en løsning for SAM-konverteringsproblemet som mange utviklere støter på når de først begynner å bruke RxJava 2.0 med Kotlin.

For å pakke opp ting, oppretter vi et program som viser hvordan du kan bruke RxJava til å løse noen av problemene du møter i virkelige Android-prosjekter.

Hvis dette er din første smak av RxJava, så underveis vil jeg også gi all bakgrunnsinformasjon du trenger for å forstå kjernen RxJava-konseptene. Selv om du aldri har eksperimentert med RxJava før, ved slutten av denne artikkelen, får du en solid forståelse av hvordan du bruker dette biblioteket i prosjektene dine, og du har opprettet flere arbeidsapper, ved hjelp av RxJava, RxKotlin, RxAndroid og RxBinding.

Hva er RxJava, uansett?

RxJava er en åpen kildekodeimplementering av ReactiveX-biblioteket som hjelper deg med å lage programmer i den reaktive programmeringsstilen. Selv om RxJava er utviklet for å behandle synkron og asynkron datastrøm, er den ikke begrenset til "tradisjonelle" datatyper. RxJavas definisjon av "data" er ganske bred og inkluderer ting som cacher, variabler, egenskaper og til og med brukerinnspillingshendelser som klikk og swipes. Bare fordi søknaden din ikke håndterer store tall eller utfører komplekse datatransformasjoner, betyr det ikke at det ikke kan være til fordel for RxJava!

For en liten bakgrunn på bruk av RxJava for Android-apper, kan du sjekke ut noen av mine andre innlegg her på Envato Tuts+.

Så hvordan fungerer RxJava?

RxJava utvider Observer-programvareutformingsmønsteret, som er basert på begrepet Observers and Observables. For å opprette en grunnleggende RxJava data pipeline, må du:

  • Opprett en observerbar.
  • Gi Observable noen data å sende ut.  
  • Lag en observatør.
  • Abonner Observeren til Observable.

Så snart Observable har minst en Observer, begynner den å sende data. Hver gang Observable utsender et stykke data, vil det varsle den tildelte Observer ved å ringe onNext () metode, og observatøren vil da typisk utføre noe tiltak som svar på denne datautslipp. Når Observable er ferdig med å sende data, vil den varsle Observer ved å ringe onComplete (). Den Observable vil da avslutte, og datastrømmen vil ende.

Hvis et unntak oppstår, da onError () vil bli kalt, og Observable vil avslutte umiddelbart uten å sende ut mer data eller anrop onComplete ().

Men RxJava er det ikke bare om å sende data fra en observerbar til en observatør! RxJava har en stor samling operatører som du kan bruke til å filtrere, flette og transformere disse dataene. For eksempel, tenk at appen din har en Betal nå knapp som oppdager ved trykk hendelser, og du er bekymret for at en utålmodig bruker kan trykke på knappen flere ganger, noe som gjør at appen din behandler flere betalinger.  

RxJava lar deg omdanne disse ved trykk hendelser i en datastrøm, som du deretter kan manipulere ved hjelp av RxJavas ulike operatører. I dette bestemte eksemplet kan du bruke debounce () operatør for å filtrere datautslipp som skjer i rask rekkefølge, så selv om brukeren legger seg unna på Betal nå knappen, vil appen din bare registrere en enkelt betaling.

Hva er fordelene med å bruke RxJava?

Vi har sett hvordan RxJava kan hjelpe deg med å løse et bestemt problem, i et bestemt program, men hva har det å tilby Android-prosjekter, generelt?

RxJava kan bidra til å forenkle koden din ved å gi deg en måte å skrive hva du vil oppnå, i stedet for å skrive en liste over instruksjoner som søknaden din må jobbe gjennom. Hvis du for eksempel vil ignorere alle datautslippene som skjer innen den samme 500-millisekundperioden, vil du skrive:

.debounce (500, TimeUnit.MILLISECONDS)

I tillegg, siden RxJava behandler Nesten alt Som data gir den en mal som du kan søke på et bredt spekter av hendelser: opprett en observerbar, opprett en observatør, abonner observatøren til observable, skyll og gjenta. Denne formelle tilnærmingen gir mye enklere, menneskelig lesbar kode.

Den andre store fordelen for Android-utviklere er at RxJava kan ta mye av smerten ut av multithreading på Android. Dagens mobilbrukere forventer at deres applikasjoner skal kunne multitask, selv om det er noe så enkelt som å laste ned data i bakgrunnen mens de fortsatt er lydhør overfor brukerinngang.

Android har flere innebygde løsninger for å opprette og administrere flere tråder, men ingen av disse er spesielt enkle å implementere, og de kan raskt resultere i komplisert, verbose kode som er vanskelig å lese og utsatt for feil.

I RxJava lager og administrerer du flere tråder ved hjelp av en kombinasjon av operatører og planleggere. Du kan enkelt endre tråden der arbeidet utføres, ved hjelp av subscribeOn operatør pluss en planlegger. For eksempel, her planlegger vi arbeid som skal utføres på en ny tråd:

.subscribeOn (Schedulers.newThread ())

Du kan spesifisere hvor resultatene av dette arbeidet skal legges ut, ved hjelp av observeOn operatør. Her legger vi ut resultatene til Androids viktigste viktige hovedbruddstråd, ved hjelp av AndroidSchedulers.mainThread planlegger, som er tilgjengelig som en del av RxAndroid biblioteket:

.observeOn (AndroidSchedulers.mainThread ())

Sammenlignet med Android's innebygde multithreading-løsninger, er RxJavas tilnærming mye mer konsis og lettere å forstå.

Igjen kan du lære mer om hvordan RxJava fungerer, og fordelene med å legge dette biblioteket til prosjektet ditt, i Kom i gang med RxJava 2 for Android-artikkelen.

Skal jeg bruke RxJava eller RxKotlin?

Siden Kotlin er 100% kompatibelt med Java, kan du bruke de fleste Java-biblioteker i Kotlin-prosjekter uten problemer - og RxJava-biblioteket er ikke noe unntak.

Der er et dedikert RxKotlin-bibliotek, som er en Kotlin-wrapper rundt det vanlige RxJava-biblioteket. Denne innpakningen gir utvidelser som optimaliserer RxJava for Kotlin-miljøet og kan ytterligere redusere mengden av boilerplate-koden du trenger å skrive.

Siden du kan bruke RxJava i Kotlin uten å måtte trenge RxKotlin, bruker vi RxJava gjennom denne artikkelen, med mindre annet er angitt.

Opprette enkle observatører og observables i Kotlin

Observatører og observables er byggeklossene til RxJava, så la oss starte med å skape:

  • En enkel Observerbar som avgir en kort datastrøm som svar på en knappeklikkhendelse.
  • En Observerbar som reagerer på disse dataene ved å skrive ut forskjellige meldinger til Android Studio logcat.

Opprett et nytt prosjekt med innstillingene du ønsker, men sørg for at du velger Inkluder Kotlin-støtte kryssboks når du blir bedt om det. Deretter åpner du prosjektet ditt build.gradle fil og legg til RxJava-biblioteket som en prosjektavhengighet:

dependencies implementation fileTree (dir: 'libs') inkluderer: ['* .jar']) implementering "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implementering "androidx.appcompat: appcompat: 1.0.0- alfa1 'implementering' androidx.constraintlayout: begrensningsoppsett: 1.1.0 'implementering' io.reactivex.rxjava2: rxjava: 2.1.9 '

Deretter åpner du prosjektet ditt activity_main.xml fil og legg til knappen som starter datastrømmen:

  

Det er flere forskjellige måter å opprette en observerbar på, men en av de enkleste er å bruke bare() operatør for å konvertere et objekt eller en liste over objekter til en observerbar.

I den følgende koden oppretter vi en observerbar (myObservable) og gir det elementene 1, 2, 3, 4 og 5 for å sende ut. Vi lager også en Observer (myObserver), abonnere den på myObservable, og deretter fortelle det å skrive ut en melding til logcat hver gang det mottar en ny utslipp.

importer androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import io.reactivex.Observable import io.reactivex.Observer importere io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.activity_main . * klasse MainActivity: AppCompatActivity () private var TAG = "MainActivity" overstyrer moro onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Start strømmen når knappen klikkes // start.Start () / myObservable .subscribe (myObserver) privat morsom getObserver (): Observer returobjekt: Observer overstyr moro onSubscribe (d: Disponible)  // Hver gang du ringer påNeste, skriv ut verdien til Android Studio's Logcat // override fun onNext (s: String) Log.d (TAG, "onNext: $ s")  // Kalt hvis et unntak er kastet // overstyr det gøy onError (e: Throwable) Log.e (TAG, "onError:" + e.message) // Når onComplete kalles, skriv ut følgende til Logcat // overstyr moro onComplete () Log.d (TAG, "onComplete") // Gi myObservable noen data å sende ut // privat morsomt getObservable (): Observerbar return Observable.just ("1", "2", "3", "4", "5")

Du kan nå sette denne applikasjonen på prøve:

  • Installer prosjektet på en fysisk Android-smarttelefon eller nettbrett, eller en Android Virtual Device (AVD).
  • Gi Start RxJava-strømmen trykk et klikk.
  • Åpne Android Studio's Logcat Monitor ved å velge Android Monitor tab (hvor markøren er plassert i følgende skjermbilde) og deretter velge logcat tab.

På dette tidspunktet begynner Observable å sende sine data, og Observer vil skrive ut meldingene til Logcat. Logcat-utgangen bør se slik ut:

Du kan laste ned dette prosjektet fra GitHub hvis du vil prøve det selv.

Kotlin Extensions for RxJava

Nå som vi har sett hvordan du oppretter en enkel RxJava-rørledning i Kotlin, la oss se på hvordan du kan oppnå dette i mindre kode, ved hjelp av RxKotlins utvidelsesfunksjoner.

For å bruke RxKotlin-biblioteket må du legge det til som en prosjektavhengighet:

dependencies implementation fileTree (dir: 'libs') inkluderer: ['* .jar']) implementering "org.jetbrains.kotlin: kotlin-stdlib-jdk7: $ kotlin_version" implementering "androidx.appcompat: appcompat: 1.0.0- alfa1 'implementering' androidx.constraintlayout: begrensningsoppsett: 1.1.0 'implementering' io.reactivex.rxjava2: rxjava: 2.1.9 '// Legg til følgende // implementering' io.reactivex.rxjava2: rxkotlin: 2.2.0 '

I det følgende eksemplet bruker vi RxKotlin toObservable () utvidelsesfunksjon for å transformere a Liste inn i en observerbar. Vi bruker også subscribeBy () utvidelsesfunksjon, da det tillater oss å konstruere en Observer ved å bruke navngitte argumenter, noe som resulterer i klarere kode.

importer 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. * klasse MainActivity: AppCompatActivity () override funn onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Start strømmen når knappen er klikket // button.setOnClickListener startRStream () privat morsom startRStream ()  val list = listOf ("1", "2", "3", "4", "5") // Bruk funksjonen toObservable () utvidelse // list.toObservable () // Konstruer observeren din ved hjelp av subscribeBy ) utvidelsesfunksjon // .subscribeBy (onNext = println (det), onError = it.printStackTrace (), onComplete = println ("onComplete!"))

Her er utgangen som du bør se:

Løse RxJavas SAM-tvetydighetsproblem

RxKotlin gir også en viktig løsning for SAM-konverteringsproblemet som kan oppstå når det er flere SAM-parameteroverbelastninger på en gitt Java-metode. Denne SAM-tvetydigheten forvirrer Kotlin-kompilatoren, da det ikke kan fungere som hvilket grensesnitt den skal konvertere, og prosjektet ditt mislykkes i å kompilere som et resultat.

Denne SAM-tvetydigheten er et spesielt problem når du bruker RxJava 2.0 med Kotlin, da mange av RxJava-operatørene har flere SAM-kompatible typer.

La oss se på SAM konvertering problemet i aksjon. I den følgende koden bruker vi glidelås() operatør for å kombinere produksjonen av to observables:  

importer androidx.appcompat.app.AppCompatActivity import android.os.Bundle import io.reactivex.Observable import kotlinx.android.synthetic.main.activity_main. * klasse MainActivity: AppCompatActivity () overstyr moro onCreate (savedInstanceState: Bundle?) super .onKreate (savedInstanceState) setContentView (R.layout.activity_main) // Start strømmen når knappen er klikket // button.setOnClickListener startRStream () privat morsom startRStream () val numbers = Observable.range (1, 6 ) val strings = Observable.just ("One", "Two", "Three", "Four", "Five", "Six") val zipped = Observerbar.zip (strenger, tall) s, n -> " $ s $ n " zipped.subscribe (:: println)

Dette vil føre til at Kotlin-kompilatoren kaster en type inferensfeil. RxKotlin tilbyr imidlertid hjelpemetoder og utvidelsesfunksjoner for de berørte operatørene, inkludert Observables.zip (), som vi bruker i følgende kode:

importer android.os.Bundle import androidx.appcompat.app.AppCompatActivity importere io.reactivex.Observable import io.reactivex.rxkotlin.Observables importerer kotlinx.android.synthetic.main.activity_main. * klasse MainActivity: AppCompatActivity () overstyr moro onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) // Start strømmen når knappen er klikket // button.setOnClickListener startRStream () privat morsom startRStream () val numre = Observable.range (1, 6) val strings = Observable.just ("One", "Two", "Three", "Four", "Five", "Six") val zipped = Observables.zip ) s, n -> "$ s $ n" zipped.subscribe (:: println)

Her er resultatet av denne koden:

Konklusjon

I denne veiledningen viste jeg deg hvordan du begynner å bruke RxJava-biblioteket i dine Kotlin-prosjekter, blant annet ved hjelp av en rekke ekstra støttende biblioteker, for eksempel RxKotlin og RxBinding. Vi så på hvordan du kan lage enkle observatører og observatører i Kotlin, rett gjennom å optimalisere RxJava for Kotlin-plattformen, ved hjelp av utvidelsesfunksjoner.

Så langt har vi brukt RxJava til å lage enkle observables som avgir data, og observatører som skriver ut disse dataene til Android Studio's Logcat-men dette er ikke hvordan du bruker RxJava i den virkelige verden!

I neste innlegg skal vi se på hvordan RxJava kan bidra til å løse virkelige problemer du møter når du utvikler Android-applikasjoner. Vi bruker RxJava med Kotlin for å lage en klassiker Melde deg på skjerm.