Android-dagi REST ilovalari uchun eng yaxshi RxJava operatorlari

RxJava standart to'plamida juda ko'p turli xil operatorlar mavjud. Ulardan ba'zilari haqiqatan ham mustahkam va ulardan foydalanish murakkab, boshqalari esa juda oddiy. Ammo ko'p RxJava operatorlarida umumiy bo'lgan bir narsa bor:

Ularning ko'pchiligini hech qachon ishlatmaysiz

Har kuni RxJava-da barcha ishlarni bajaradigan Android-ning ishlab chiqaruvchisi sifatida, men ko'p marta zip () operatoridan foydalanishga harakat qildim va har safar buni uddalay olmadim. Men har doim undan yaxshiroq narsani topdim, yoki ushbu operator ushbu holat qamrab ololmaydigan vaziyatni topdim. Zip () ning umuman foydasi yo'q, demayman, kimdir sizga yoqishi mumkin va agar u sizga ishlasa - bu juda yaxshi. Ammo men juda foydali deb hisoblagan ba'zi operatorlarni muhokama qilaylik va ular juda qulay va REST asosidagi dasturda ishlatilishi oson.

Va bu erda ular:

  • share ()
  • takrorlash (1) .refCount ()
Agar siz ularning nima qilayotganini oldindan bilsangiz, siz ham menga chapak chalib qo'yishingiz va shu erda o'qishni tugatishingiz mumkin.

Issiqmi yoki sovuqmi?

Ko'pincha tushunish qiyin bo'lgan eng muhim narsalardan biri bu issiq yoki sovuqmi. Buni tushuntirib beradigan juda ko'p ajoyib maqolalar mavjud va men buni yana qilishni xohlamayman, buning o'rniga men amalda qanday ishlashini ko'rsatadigan misollarni ko'rsataman.

Oxir-oqibat, sizning qo'ng'irog'ingiz kuzatiladigan issiq, sovuq yoki issiq bo'ladimi?

Yo'q.

Buning hammasi muhim: agar u ishni bajarsa.

Umuman olganda, siz ikki xil kuzatiladigan narsalarga ehtiyoj sezasiz:

  • oxirgi chiqarilgan qiymatni eslab qolishi va uni barcha yangi obunachilarga tarqatishi kuzatiladi,
  • kuzatilishi mumkin, bu uning oxirgi chiqarilgan qiymatini eslamaydi.

Gap arzon. Menga kodni ko'rsating.

Aytaylik, bizning dasturimizda ba'zi ma'lumotlarni yuklab olib, uni namoyish qilishni xohlaymiz. Buning eng oson usulini tasavvur qilaylik:

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

Mana. Endi xatolarga ishlov berishga ruxsat beraylik:

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

Ajoyib. Shuningdek, eng yaxshi UX uchun yutuqlar va bo'sh ro'yxatni qo'shaylik:

val usersObservable = service.getUsers ()
         .subscribeOn (networkScheduler)
         .observeOn (UiScheduler)
usersObservable
         .filter {it.isNotError ()}
         .bizni bekor qiling {view.update (it)}
usersObservable
         .filter {it.isError ()}
         .bizni bekor qiling {view.showErrorMessage ()}
usersObservable
         .map (noto'g'ri)
         .start bilan (haqiqiy)
         .subscribe {progressLoading.visibility = it}
usersObservable
         .map (it.isEmpty ())
         .start bilan (yolg'on)
         .bizlarni bekor qiling {emptyMessage.visibility = it}

Endi ... ushbu kodda biron bir noto'g'ri narsa bormi? Biz sinab ko'rishimiz mumkin.

@Test
qiziqarli test () {
    val usersOrError = Observable.just (listOf ("user1", "user2"))
            .mergeWith (Kuzatiladigan. har doim ())
            .doOnNext {println (bu)}

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

}

Yuqoridagi testda REST so'rovi o'rniga Observable.just () mavjud. Nima uchun birlashtirishWith (hech qachon ())? Chunki biz har bir obunachiga obuna bo'lish imkoniyatiga ega bo'lishimizdan oldin, biz kuzatib borishni istamaymiz. Shunga o'xshash holatni (hech qachon to'xtab bo'lmaydigan) foydalanuvchi so'rovini bosish orqali ba'zi so'rovlar qo'zg'atilganida sezish mumkin. Ushbu holat keyinchalik maqolada ko'rib chiqiladi. Bundan tashqari, oldingi misolda ishlatilgan to'rt kuzatuvchi faqat obuna bo'lish uchun soddalashtirilgan (). Biz rejalashtiruvchilar qismiga e'tibor bermasligimiz mumkin, chunki hamma narsa bitta ipda sodir bo'ladi. Yakuniy natija:

[user1, user2]
[user1, user2]
[user1, user2]
[user1, user2]

Kuzatilishi mumkin bo'lgan foydalanuvchilarning har bir obro'si println () ni qo'zg'atdi, ya'ni haqiqiy hayotda biz bitta o'rniga to'rtta so'rovni ishga tushirdik. Bu juda xavfli vaziyat bo'lishi mumkin. Tasavvur qiling-a, agar zararsiz GET so'rovining o'rniga biz POSTni amalga oshirsak yoki ma'lumotlar yoki dastur holatini o'zgartiradigan boshqa usulni chaqirsak. Xuddi shu so'rov to'rt marta bajariladi va masalan to'rtta bir xil post yoki sharhlar yaratiladi.

Yaxshiyamki, biz uni (1) .refCount () qo'shib osongina tuzatamiz.

@Test
qiziqarli `testlarni takrorlash refCount operatorlari '() {
    val usersOrError = Observable.just (listOf ("user1", "user2"))
            .mergeWith (Kuzatiladigan. har doim ())
            .doOnNext {println (bu)}
            .replay (1)
            .refCount ()

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

}

Ushbu test natijasi:

[user1, user2]

Ajoyib, biz obunamizni barcha abonentlar bilan baham ko'rdik. Endi keraksiz bir nechta so'rovlar qilish xavfi yo'q. Qaytadan (1) .refCount () o'rniga o'rniga share () operatori yordamida bir xil narsani kuzatish imkonini beradi.

@Test
kulgili "test ulash operatori" () {
    val usersOrError = Observable.just (listOf ("user1", "user2"))
            .mergeWith (Kuzatiladigan. har doim ())
            .doOnNext {println (bu)}
            .share ()

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

}

Ajablanarli (yoki yo'q) natija avvalgisi bilan bir xil:

[user1, user2]

Share () va takrorlash (1) .refCount () o'rtasidagi farqni ko'rish uchun yana ikkita sinovni o'tkazaylik. Bu safar biz foydalanuvchi tomonidan bosilgan voqeani olgandan keyin soxta so'rovimizga qo'ng'iroq qilamiz. Klik hodisasi aPublishSubject tomonidan masxara qilinadi. Qo'shimcha qator: doOnNext {println ("1")} foydalanuvchilarniOrError-dan voqeani qaysi obunani olganligini ko'rsatadi.

Birinchi testda ulashish () va ikkinchisini takrorlash (1) .refCount-dan foydalaniladi.

@Test
kulgili `sinov yordamida ulash operatori '() {
    val clickEvent = PublishSubject.create  ()

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

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

    clickEvent.onNext (Any ()) // chertish amalga oshiriladi

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

}

Natija:

1
2

@Test
kulgili `testni takrorlash bilan qayta to'ldirish operatorlari '() {tugmachalari bilan
    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 (Any ()) // chertish amalga oshiriladi

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

}

Natija:

1
2
3
4

Xulosa

Share () va takrorlash (1) .refCount () REST so'rovlarini bajarish uchun muhim operatorlar va boshqalar. Har safar bir nechta joyda bir xil kuzatib borish kerak bo'lsa, bu borishning eng yaxshi usuli. O'zingiz kuzatib boradigan so'nggi voqeani eslab, uni har bir yangi abonentga etkazishingizni xohlasangiz yoki faqat bir martalik operatsiya bilan qiziqsangiz, o'ylang. Haqiqiy hayotga oid ba'zi amaliy misollar:

  • Ma'lumot olish uchun foydalaniladigan getUsers (), getPosts () yoki shunga o'xshash kuzatuv, ehtimol, (1) .refCount (),
  • updateUser (), addComment () - bu bir martalik operatsiyalar va bu holda share () yaxshiroq ishlaydi,
  • Kuzatiladigan - RxView.clicks (ko'rish) ga o'ralgan klik hodisasini o'tkazish - ulash () operatoriga ega bo'lishi kerak, shunda klik voqeasi har bir abonentga uzatiladi.

TL; DR

  • share () -> barcha obunachilar uchun kuzatilishi mumkin bo'lgan ulushlar, yangi obunachilarga so'nggi qiymatni keltirib chiqarmaydi
  • takrorlash (1) .refCount () -> barcha obunachilarga kuzatiladi va har bir yangi abonentga so'nggi qiymatni beradi

Agar sizga mening ishim yoqsa ❤ tugmasini bosing va sharhlardagi fikrlaringizni bildiring.