A legjobb RxJava operátorok REST alkalmazásokhoz az Androidon

A RxJava csomagban sok különféle operátor található. Néhányuk valóban robusztus és bonyolult használatban, mások meglehetősen egyszerű. De van egy dolog, amely sok RxJava operátor közös:

Legtöbbjük soha nem fogja használni

Mint mindennapi Android fejlesztő, aki az összes dolgot elkészíti az RxJava-ban, sokszor igyekeztem a zip () operátort használni, és minden alkalommal elmulasztottam. Mindig valami jobbat találtam, vagy olyan helyzetet, amelyet ez az üzemeltető nem fog fedezni. Nem azt mondom, hogy a zip () -nek egyáltalán nincs szokása, valakinek tetszik, és ha ez az Ön számára működik - Nagyszerű. De tárgyaljuk néhány olyan operátort, amelyet rendkívül hasznosnak találok, és ezek nagyszerűek és könnyen használhatóak a REST alapú alkalmazásokban.

És itt vannak:

  • részvény()
  • visszajátszás (1) .refCount ()
Ha már tudja, mit csinálnak, akkor hagyhat nekem is tapsot, és ezen a ponton fejezheti be az olvasást.

Meleg vagy hideg ?

Az egyik legfontosabb dolog, amelyet gyakran nehéz megérteni, az, hogy a megfigyelhető meleg vagy hideg. Sok nagyszerű cikk elmagyarázta ezt, és nem szándékozom újra megtenni, ehelyett példákat mutatok be, hogy hogyan működik a gyakorlatban.

Végül is, nem számít, hogy hívja-e valamelyik megfigyelhető forró, hideg vagy meleg hívást?

Nem.

Csak az számít: ha megcsinálja a munkát.

Általában kétféle megfigyelésre lehet szükség:

  • megfigyelhető, amely emlékszik az utolsó kibocsátott értékre, és azt minden új előfizetőnek továbbítja,
  • megfigyelhető, amely nem emlékszik az utolsó kibocsátott értékére.

Beszélni olcsó. Mutasd meg a kódot.

Tegyük fel, hogy alkalmazásunkban néhány adatot le szeretnénk tölteni és megjeleníteni. Képzeljük el a legegyszerűbb módszert erre:

val usersObservable = service.getUsers ()
         .subscribeOn (networkScheduler)
         .observeOn (UiScheduler)
         .subscribe {view.update (it)}
         .subscribe {view.update (it)}

Ott. Tegyük fel a hibakezelést:

val usersObservable = service.getUsers ()
         .subscribeOn (networkScheduler)
         .observeOn (UiScheduler)
usersObservable
         .filter {it.isNotError ()}
         .subscribe {view.update (it)}
usersObservable
         .filter {it.isError ()}
         .subscribe {view.showErrorMessage ()}

Nagy. De adjunk hozzá egy előrehaladási eseményt és egy üres listát a legjobb UX-hez:

val usersObservable = service.getUsers ()
         .subscribeOn (networkScheduler)
         .observeOn (UiScheduler)
usersObservable
         .filter {it.isNotError ()}
         .subscribe {view.update (it)}
usersObservable
         .filter {it.isError ()}
         .subscribe {view.showErrorMessage ()}
usersObservable
         .map (hamis)
         .startWith (igaz)
         .subscribe {progressLoading.visibility = it}
usersObservable
         .map (it.isEmpty ())
         .startWith (hamis)
         .subscribe {emptyMessage.visibility = it}

Most ... van valami baj ebben a kódban? Kipróbálhatjuk.

@Teszt
szórakoztató teszt () {
    val usersOrError = Megfigyelhető.just (listOf ("user1", "user2"))
            .mergeWith (Observable.never ())
            .doOnNext {println (it)}

    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()

}

A fenti tesztben a REST kérés helyett azObservable.just () van. Miért mergeWith (soha ())? Mivel nem akarjuk, hogy a megfigyelhető részletünk teljes legyen, mielőtt minden előfizetőnek lehetősége van előfizetésre. Hasonló (soha véget nem érő megfigyelhető) helyzet akkor is észrevehető, ha valamilyen kérést a felhasználó kattintási bemenete vált ki. Ezt az esetet később a cikk tárgyalja. Az előző példában használt négy megfigyelhető anyagot szintén egyszerűsítettük, hogy csak feliratkozhassunk (). Az ütemezők részét figyelmen kívül hagyhatjuk, mivel minden egy szálban történik. A végeredmény:

[felhasználó1, felhasználó2]
[felhasználó1, felhasználó2]
[felhasználó1, felhasználó2]
[felhasználó1, felhasználó2]

A userOrError minden megfigyelhető előfizetése kiváltotta a println () -ot, ami azt jelenti, hogy a valós életben csak négy kérést indítottunk el egy helyett. Ez nagyon veszélyes helyzet lehet. Képzelje el, ha a potenciálisan ártalmatlan GET-kérés helyett POST-ot készítünk, vagy más módszert hívunk meg, amely megváltoztatja az adatok vagy az alkalmazás állapotát. Ugyanazt a kérést négyszer hajtják végre, és például négy azonos üzenet vagy megjegyzés kerül létrehozásra.

Szerencsére könnyen megjavíthatjuk a replay (1) .refCount () hozzáadásával.

@Teszt
szórakoztató "tesztismétlés refCount operátorok" () {
    val usersOrError = Megfigyelhető.just (listOf ("user1", "user2"))
            .mergeWith (Observable.never ())
            .doOnNext {println (it)}
            .replay (1)
            .refCount ()

    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()

}

A teszt eredménye:

[felhasználó1, felhasználó2]

Nagyszerű, hogy sikeresen megosztottuk előfizetésünket az összes előfizető között. Most nincs fenyegetés szükségtelen többszörös kérések benyújtására. Kipróbálhatjuk ugyanazt a megfigyelhetőt a share () operátorral, a replay (1) .refCount () helyett.

@Teszt
szórakoztató "teszt megosztás operátor" () {
    val usersOrError = Megfigyelhető.just (listOf ("user1", "user2"))
            .mergeWith (Observable.never ())
            .doOnNext {println (it)}
            .részvény()

    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()
    usersOrError.subscribe ()

}

Meglepő módon (vagy sem) az eredmény megegyezik az előzővel:

[felhasználó1, felhasználó2]

Ha meg szeretnénk nézni a különbséget a share () és a replay (1) .refCount () között, tegyünk még két tesztet. Ezúttal meghívjuk a hamis kérésünket, miután megkaptuk a felhasználó kattintási eseményét. A kattintási eseményt az aPublishSubject gúnyolja. Kiegészítő sor: doOnNext {println ("1")} megmutatja, melyik előfizető kapta meg az eseményt a usersOrError-tól

Az első teszt a share () és a második replay (1) .refCount használatával történik.

@Teszt
szórakoztató `teszt megosztás operátor kattintással` () {
    val clickEvent = PublishSubject.create  ()

    val usersOrError = clickEvent
            .flatMap {Observable.just (listOf ("user1", "user2")))}
            .részvény()

    usersOrError.doOnNext {println ("1")} .subscribe ()
    usersOrError.doOnNext {println ("2")} .subscribe ()

    clickEvent.onNext (Bármely ()) // végrehajtja a kattintást

    usersOrError.doOnNext {println ("3")} .subscribe ()
    usersOrError.doOnNext {println ("4")} .subscribe ()

}

Eredmény:

1
2

@Teszt
szórakoztató `teszt visszajátszás refCount operátorok kattintással` () {
    val clickEvent = PublishSubject.create  ()

    val usersOrError = clickEvent
            .flatMap {Observable.just (listOf ("user1", "user2")))}
            .replay (1)
            .refCount ()

    usersOrError.doOnNext {println ("1")} .subscribe ()
    usersOrError.doOnNext {println ("2")} .subscribe ()

    clickEvent.onNext (Bármely ()) // végrehajtja a kattintást

    usersOrError.doOnNext {println ("3")} .subscribe ()
    usersOrError.doOnNext {println ("4")} .subscribe ()

}

Eredmény:

1
2
3
4

Következtetés

Mind a share (), mind a replay (1) .refCount () fontos operátorok a REST kérések kezeléséhez, és még sok más. Minden alkalommal, amikor ugyanazon a megfigyelésre több helyre van szüksége, ez a legjobb módja annak, hogy menjen. Gondoljon csak arra, ha azt akarja, hogy a megfigyelhető emlékezzen a legfrissebb eseményre, és továbbadja minden új előfizetőnek, vagy esetleg csak az egyszeri művelet érdekli. Íme néhány valós alkalmazási példa:

  • getUsers (), getPosts () vagy hasonló megfigyelhető elem, amely az adatok begyűjtésére szolgál, valószínűleg usereplay (1) .refCount (),
  • Az updateUser (), az addComment () viszont csak egyszeri műveletek, és ebben az esetben a share () jobban teljesít,
  • A megfigyelhetőbe csomagolt átmenő kattintás eseménye - az RxView.clicks (nézet) - rendelkeznie kell share () operátorral is, hogy megbizonyosodjon arról, hogy a kattintási eseményt minden előfizető közvetíti-e.

TL; DR

  • share () -> megosztja a megfigyelhetőt minden előfizetővel, nem bocsát ki legújabb értéket az új előfizetők számára
  • replay (1) .refCount () -> megosztja a megfigyelhetőt minden előfizetővel, és minden új előfizető számára legfrissebb értéket ad ki

Ha tetszik a munkám, nyomja meg a ❤ gombot, és tudassa velem, mit gondol a hozzászólásokban.