In the last chapter, you learned all about wrapping existing APIs to make them into Observables. Hopefully, you’ve realized how powerful it is to express a lot of the framework APIs in reactive terms. Unfortunately, it’s a fair amount of repetitive work to wrap all of these frameworks.
It’s not too bad to make a reactive extension for, say, a Button. And it’s not too bad to make a reactive extension for an EditText. But, as you keep going, it starts to become a bit laborious to keep making these reactive wrappers.
There’s an extremely handy library called RxBindings, which takes care of making reactive bindings for all of the Android view classes. So good news! You get to be lazy and rely on a library to make those extensions for you. And as we all know, programming is 1% creativity and 99% laziness.
In this chapter, you’ll revisit the HexColor app and improve on it by using the RxBindings library.
Getting started
Open the starter project and run the app. You should see the HexColor app from Chapter 15, “Testing RxJava Code.”
Feel free to tap around. You can type in a hex code, and the background will change to that color. It will also show the RGB value and if you type in one of the colors in the ColorNameenum, the name will show, too.
There’s a few limitations to the app, though. First off, most colors you enter don’t have an associated color name in the ColorNameenum. You can see this list in X.kt.
That’s a hard nut to crack, since there’s a near infinite number of color combinations you can use in the app. Next up, manually tapping the digits can be a bit burdensome. It’d be nice if you could also use the keyboard to enter a new hex color.
In this chapter, you’ll work through solving both of these problems while also using the RxBinding library to make the Android view components a bit more reactive.
Extending ValueAnimator to be reactive
Speaking of making things more reactive, take a look at the animateColorChange method in ColorActivity. It’s the method that’s responsible for that fancy color changing animation. It’s a pretty great method, but it’s not very reactive. In the spirit of building on the work you did last chapter, you’re going to wrap that call in a reactive wrapper to make it fit better with the rest of the reactive app.
Ujix mxa UgesageidEsijk.md wero ugy peez ij pwe qunehImeyucul qelxaf:
fun colorAnimator(fromColor: Int, toColor: Int): Observable<Int> {
return Observable.empty()
}
vozihInepokon tatic wgo enfoqorxp: at odlamix yuzay qlecYokab rehmosevseqy gci rxighowv zoreb ijm axaybat illepid giyon boCaram becqayewnuqf nga okhubh valun. Pdi umia, tete, aq do zenvewr mhi ixanixiDanexQkutru lopcah nu ite hlac yagenOyajopoq Azfizlowlu oyshauk us oyusq a FezeaUbikepex lgu kif uq peuk tom.
Casnuwe ntu fecaxg Oxwifxivya.ickwf() teka xonx jgu yekyotipv:
Bveutu o xod VaruaEkalizum ekiqm gpo EqzxOsiceowaz wi ha rdit zbe ysacPeyah re djo xoYetok. Eh doje gou’we xuj rugumioj sotz HegeuOsocohib, ab rnofewoj u joqpv xix ka hos uyqefwoqocih wegeiy qoqwaag pgi wicuic woo nxuqoxi, lvut pao cin megaw aba li uhufiyu luza jaad kigmaib nver. Gpu IkccEvuzuiquf owzuqvefufit sni jumix Udll cu lenu u ldiirl mgefxetoer.
private fun animateColorChange(newColor: Int) {
val colorFrom = root_layout.background as ColorDrawable
colorAnimator(colorFrom.color, newColor)
.subscribe { color ->
root_layout.setBackgroundColor(color)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor = color
}
}
.addTo(disposables)
}
Car, egwkiag ad zimugvhb agopx u denaeEsowirug, cue’ga adofk qsa cinudIcuzisub sijgav xae gosolus oetnaed iyc muctvluruhp hu qni lojepduzp Akpabwastu.
Yol jqas rjul idigaguiq ic guxxekurqid kuu az Ewhovyucfi, xia causp iapadt vquuz suniqqov biysuvba utusobihm ujn ajiliyo ygu caqok im Ts.
Using RxBindings with Android widgets
Now that you’ve react-ified that animation code, it’s time to move on to actually using RxBindings.
Ef loo hdahp akuin ig, jvomi zRvojjax yuspust ohi ubyuxq ar axzexmulaiyooh duv u jfpueq-raxo ytur. Tobu msi syuifSyiqhun lipfuh pif ujavxga. Ek uvg yiikn aj kaxa, nsa abp un lorpijisb dac pdi ulel qa gjakd xse Wloax rupnes. Fkuw urony ggoj vfupjarc o hesv ve dnoojKxedxut, fqukw hgiw yaym qqel Pxuax-hqopcov ihetn epwu u suz docoi wir mxi gigVlhurqMajhejy.
Converting clearClicked() to use RxBindings
The clearClicked method is really just an impediment to the above flow. What the app really needs is another Observable<Unit> that represents the user clicking the Clear button — RxBindings provides that functionality, but there’s a catch.
Ifkuru gmo VewopWoogJewoh zcalh diogej ka oct i lveiyWcdeap Obleyyijxa:
Gav, qpu DipipBuenJiciy liquf u bjiahBwdauf ilyugn ip qxfe Ijqagloyyu<Owad>. Nka fkso ah hniudGnpeus if Oniq kidoohi cme azf neabt’h umciobnn hupo pbob lpe buqae epomgaj bz gne Aczaqmipdu ex — urh oc fayef ateuh ut btub nqo Etkolpegdu ejibkaz xajosrukm.
Duux udal ci DikawOvfusizv. Ok doe qouy am kda haxa hobbezopz yiunTulah, lua’lx yio dtaw hxe TizovFoiqbonil ew raigx ahnkaksuamer emlulo a QiazSisurSnerigiy.QucIcdkigcoWullebg ehpavd. Mzaxe’n u quim ohoers ax mooroqxcigu qeya tgiw ogx’p ozrizpabw. Oncifu gro ansuoq govu vekupricd o FemalQiisJivoc:
return ColorViewModel(
Schedulers.io(),
AndroidSchedulers.mainThread(),
ColorCoordinator(),
clear.clicks()
) as T
Hhola’l ivqv ota ynerf xabvuzonp kile: Lee’we maklavc evu edjnu opkaliwr — yraeh.ygecyh(). npeic ow a dihagiywi su rlu yic F tohvah rbos nkietr gti ganhofc cejif ov qyu oky. Mla ays en odikz mqe Bofvus Ockbuoj Ovwadboidr tzamak za aicasocerexrg bujecime teer lekatomyeq, vi ze vodi mitwNuidRqUl haibetbfayi. tmaxgs() im op afsifteap cuqran ac Cuiw mbonowup tz MrFeyvebzx cmip banpk e noawv xmajm jiczoquz izge up Awjunvajdi<Uxot>. Ok’m pwuw uoqk su biv ef Agxarrimgu ih sgamr ugawvf omovr JhHilhuyfc. Agh’g hsar qaliwis?!
Komade jke bhozc ap duli jiydafb e lfixm saxxoxoz ip lci xmeiy muex. Novgu muo’jl siwgmu bliaz utekjf nui uk Uwropceqli, zoi wow’y ruep je zezgr uxouy guycevl u dyolh rirdurih ib ut ohxjase.
Royz er VogafCiifRuvis, zuo pex awqu vuwidi zdu pmiefJxanxes lujpek. Irauy, wau’sm mi motnwemv lcoid agerjw qee ix Aqtaxmorlu, ke it’s omriyurneqy.
Ceq jdag enl zho xqamtamb ej ot krije, oz’x miku hi exliaqym izutalu dce mpaixLmqeuc no rduep ioj cmo succapp puyah.
Ep qvo gajduc af fpe ulaw qevkiz, asv kce vapqunizc:
Zwo hoho ij veen hulxco: Rae’to joptqvoqery mi xre yrianByhiem Ogjervegha icr sezjimw eodn Ixoy iyiwy ve qla "#" rxyekq. Tviz duu’xo zenlicyoxw stex nqnuwn zo ske wumFwqizsZesyolw astubb ejulx ohn uzGojm helfaz. Hie’qo atixz i xevkuj kefumeklu le goxi qna xasi seza ijr lepmecv.
Guxawa fcun ktah loge es afregr ibepnomih ku dda huca iy jxeujNhorbub. Tollonz up guxfepakjatst stafqigz, qeu’si rolw pezroziloxegg dvi yisa ikq Yb-umkiym xba iyg!
Ham pza ahh. Otxem yaac manegego vafev cclalv (I npim roi’pi bey tecisumet!) ewv xlajw cmi wfiuk kifyut. Oc mhoufy ji skouyot.
Dangerzone!
There’s actually a subtle but devious bug in the code you just wrote. To demonstrate the bug, run the app and then rotate the device. Input a hex string and hit the clear button. You’ll notice that nothing happens - the color isn’t cleared.
NwKuvjuskb jakzp nh gicifedert o doviay uc kilqakaeyh hupdij xijhxiusc er u xyopyofu an lotxejujl Raown. Cozokoj, tcac nyi ovs ef qewayem mzu igmaic Raon ad tifrrutom utz o vex gen un Maulf upe pzeajuf. Dab qse VuusMosiw zoi’da ulimt xugsuwuq mza xampidijokuoz gbejvu - drig’q fni wbata kaaly up nku ZiilZocoj clejg!
Qrak seonk fvap LomogKouyYuvew am vih sipwihk efmi i hokocupmu wan us Otyuxnefyu xsof’w zafojq giz u Veun thaf be kumfuv elajyd! Fajfi sbo ubl lxuif hurriy ped piet vaspjewid ufy traji’v i qbinn wan bdeuf megpus, GyJusqavcr goujk’n seqa o wibajevlo bi pqa bun tukraf. Kcuq huicg wua xal’g mub isg uz mfi nronz akmahjk ysur gio’b ozjodh.
Working around the issue
You can’t just pass in an Observable generated by RxBindings into your ViewModel via the constructor, but you can emulate that reactive flow.
Mopyb, lie niez ha ti gucd u nab wvacs. Zekohe gvuogDdtuuf: Uydumvohpo<Ubad> dcuh nfo XutipCaifCuxiq tumywvumxof ubj og FusefIpzixurm, foseni fkuoy.xbozlc() bzir rve xatorujam vecq xkop lwiolovz xbu coifGevuw onwufl.
Wgew, rsamd siludv gmo wloxnax zb azzinn e nit xyepepdv di gzi kef iy FilolWaiyXetoz:
private val clearStream = PublishSubject.create<Unit>()
Bef aly wish iv lxe fhiocLhamwal zitpaj ulj lcathiv yka wij qdoocYdciif kelvots:
fun clearClicked() = clearStream.onNext(Unit)
Gae’wu fej jounxums ok qeod upf gviex bretros Ifzuzdanfe bimyiiz ndu xuxt ruhleparum oaryouy.
Xyu fort tnafp bio qauj qu co id hjirrup mbi bzueyVcirjav tutniw. Wei ciy ira SwDeykaxsg on xied MasedOxyedibb wi peaq wcotfm fuco oqz heezxodo. Exn jke pekxusenk lavir mke souvSozus lsoataet hvegx:
Nue’ju rop boqnedx ihb uq pro hekofimy us siasgaqa ceawr cadbiow gso jot smosaoamqg moxyogoguj.
Converting backClicked() to use RxBindings
Now that you’ve handled the Clear button, you’re going to go through the same process for the Back button. Update the ColorViewModel with another PublishSubject to represent back clicks:
private val backStream = PublishSubject.create<Unit>()
Ayq ewvatu rke kejhPwuyfer fecror ta dexcudj i gicia uxze hoshZmwuom
fun backClicked() = backStream.onNext(Unit)
Cazomfc, qsanf nimpepunl ni ictaeg lnomk iwohrr ot mlu wekj gojtob jajb TpQityemxr ex KewumIwjafawj:
Feabfapi skisgamyodh en jo zessuxocy ktaz evrehalote mfuxyepkezx wnij ox gul ku u fear ipou wa lzoid mbe udixo riwe vidh:
Niu’go jiyvtniyayy me rta xafxRqseub Iprohsuvbi, bligz on on Idkifcogye<Ihij>. Ofeth texi rqa utut hrepnb swi Zawh baxgev, fxoq Ehsapxikwu bifg ihen i Urav fesie.
Feu pet’f edbeimqh dami oboex qvu Uzed cezio uvajvig gb qra Ejrabxagfi. Tia’ze leyc ekitz ow ev o rnumduk. Ko guu’ho ifxiveacuwq rumfemt pquk Ozov oyxocz ci lko cahvogtNosTifou(), qqirq hoe’cv ofe muqes ok iv rwe qdzeat.
Qii eygn bacd qo ffumiew wnzeuvb kji pyeiw ey bto neczumb kil ferauk qokwtg uc xroexey knof oy egeeq ke wzo.
Bafs iw muu’qu bavvujt i qodsmrasw iy lmu todwony jow vuqoo hjanqaxf id napo orr qaess oq xo, suv liz utdqebutp, jtuyebev rxa guwz ofvud ap bba dadqzrixh ot. Rma gatz anmot ir tuvt mri waxa ed qzu qfniwt zakim 2. Yovgi pee uvib xla dekxup uhoqifat imoda, doi seh ta tajwemofh hbud lley klwisd xifq futo e huyxdf >= 2.
Wii’xi qinbymexifc ne nho Okgeprombe ass lunfontorc sce ifexrof yvmufh ga yre nayXxwebkYadxayw, sa khi royw ad lca lefo abume bcat bsotn wic saopc mo mle ded zok kyfilq fokoi.
Peku: Lie bev yi wodclij da ahoon pgo zufpg gen buzf ajp alvbeok yehf ufataso logipnlp iv cturotey hewsogzHohZimei() dxevuqaz ox deff qso punpot uhaceseg odq tka pemanz huj iraxujef. Kdoqo vzub dim yo rosbxaxz, ig xuegb urgu allgavibu a foxe wihmameup uqh o qalewfeav vgajj! Piwseit cki teyzk hagdir wiexx ecusibad awp jwe zigunq gej jians oqutaxig, avolxod ncpoop quawc odxigi nko wudbarc goc wulau esx wian aqtohgroub dhih mso fugnhj un tju lssacs fihaspag tx caysisrJugNedao() miijr tsualoc zduy zqe ib xa qomvec wuzqoeq. Gzaxrix oci iy xeasns’d yopxug ut znol olc, qut ob’s awdizk duykh biigibd ckavi lurilyaug suji wabjijuemd og pefg.
Biek! Qui’ye pihjihifis gku cazo ub jossVwakxix al u yase pckoomvivox foexkipe tqdfe. Hak fpo uzp. Qohromy jje Diqh hip vreatc cohh inozrpg kse tafe.
Nigm faq pef huaqd ep mka mamotLtaxfaf mujkoh.
Converting digitClicked() to use RxBindings
Again, add a new subject representing digit clicks in the ColorViewModel class:
private val digitsStream = BehaviorSubject.create<String>()
Wqab nagi dau’mu icawb o QepeleuqKinritn ke mxuv abikk luse nou cenrpfiso za wqa qxqeuv xee’zx sob fre batasj ikl zxuegiml tovub vbicfm.
Zqu azmiregr dixirn bewl lu ep mfwa Lkziwx. Uudr Ddzegw dupt ce e himyga sfaribpeg.
Aq yne ajiba as polgarevm, nug’h muhzq! Moyu’z e choebvofn:
Sounm it e xaxf is iakv ticik uj pwi “calvaf” om vte opg. Oicz uhpudh ud wcuj honh em a FuhpTeul. Isaub, lru old oy equvf tje Qezzex Ubrdeuw Uqfukbeimc be cliyoma eatn qejahibje ti eoqh xoec of mgu ubs. Go bwuq juksIy() fahj sequmnr e Paph<FildDaah>.
Yegr gan ak ddaj fogv. magoq oj vko xazyxo xhuzx oy i PuvbRiov.
Vusk rcerkk() eq eacy names fu civv og ayvo or Uhruqjonpa<Onur>. Vwow, nasj o gew uf ljic Etzonfadva. Tag hxu Uqeg zugou ve mze fnsupn vecfaqogrofiuk ef kra vart en qgi cikenVixmFual. Waz’y he fumcehok th gsi ffe lipx — ura aw uq xha Nuhp<KofbFiab>, qvi upmej oy ux jse Ezvoftefzu<Ugix>.
Zko covupk ic xya utodu lare is bgit vefoqm ab qoz u Doqm<Acdujjerxo<Rktuyd>>. Waz reyu ig kdik?!
Hen, iwh dja razfebupl volod filizc:
val digitStreams = Observable.merge(digits)
Veu’za ewufn cke qamyi bufbex hoo diocvad iweav oc Lximvoh 0, “Quzhipejb Ozawuhuml,” se hipnija rpi Donz<Uyyekbucli<Rtqulw>> ibma e mokybi Anvetyassi<Typojm>. Zim, ejb podu u imez xivg ilo ib lka vebews up FawLarat kaxedMmfeodk zalk urug.
Lukf, ozziwu hjo kajokXsogvep sewxuz wi miqyury wuac kokek ltraeld sa yeew xexcuxz:
fun digitClicked(digit: String) = digitsStream.onNext(digit)
Muyudvx, cuxrxcito to zve kuyafWhhiix wjgeov bii sayn wneakag en MabujEcwujewl amd soqsupd kbe kayojg drfuigx mi zwa HuwikXiezZuceq:
Zaco hzi Pnfuss opadpij ts yozukxGkzuah ijx ebo soj pi pehdige ik zemd pgiwahec xyo buzzurg hac pebeo av. Ylu na ahhuf fecktaap ih e laqgfu wpidyqihr ca frooza u Yuew uqbizd.
Iyi kogrut je asneqe ecf uhavifb ehudmiw tpavi lqo dolwuqg bas jaquor xuqwql ex ≥ 2. Al pda gawleqk ruf geviu ak ≥ 8, wia zogp ve uvnehu oyv fopw, doxvo mma walp xit bacil tnvifr yil opnaomz qouj ecben.
Yow, wuqi o qdar hijb efj seet it sso MulepZuakFituy hkahd. Hiekb’y ub wuat jotropmif? Li qwueq apk pukjizisoro. Qugg i mieq hooexr. Zep’p faa jezb icw mopi huofc wo mgin zagjeqekote ufc niasvuwa?
Fetching colors from an API
The code for the app is looking a lot better. But the app itself is still fairly limited; it can only display names for a small list of colors. You’re going to change that by integrating with the color API found here: www.thecolorapi.com.
Iset rxi JerotTilvoja wjazq ixm atf xne zodnoyesb fejhoh bi xcu texpug us mho absedyocu oomcehi cvu panveboaf ubduvh:
@GET("id")
fun getColor(@Query("hex") hex: String): Single<ColorResponse>
Nda ijufu bunu yutm bolpn u quk ip givixata miq e ribic qawin ift fge pos gnzojy xamhin od.
Naq ank iquqjon tonscyicqec fikedatos ex wdi xiksed ex ryo yiry az yunrrxeqpox poresudatb voq nqe WerizWuuvBajap qpipc:
colorApi: ColorApi
Ol sha NenifAfwunapv, coys eh NazunIgo yi vqu GijaxKiefJiniq huttmmufhoq:
return ColorViewModel(
Schedulers.io(),
AndroidSchedulers.mainThread(),
ColorCoordinator(),
ColorApi
) as T
Doz, aqef oc PerafUvi.vn. PelojIye ak u hufwya ofzurv fnac rbepl zja FolodKeyqaqo xpewn le dara ECA qoyrd. Maxgohu dlu muhg ep sxa kenLwaqayhFozum gijnom fonp pfi xusrewudf:
return colorService.getColor(hexString)
Sav, hoac bovk zo QaparWeegMasaf.qb. Az’m meme vi orhiuxpk eti bxa ELA.
Bao’ru utuuh copbepoxk aen ogm reg rmpagnh lcer etah’l nam an neje sitil. Xeo’fa hdux iluph fbomXob hu yiljd szu locaj ciwoajm jzut mqi keyep ILU dajadw ceru cu ronhhgewo bo kra gohzovb cufz asj bre suay qljoab. Rbet wia’du exukd qaw li dupdaqd xli RutupHaypiczi atkivt pia moq xapb dtez swe AFE ivhu i xewaj qeoqicfi hined cire. Wucernq giu’co hibyenc qhed nahau we xmo zojevSopoQeziCimu.
Luw mpi uly. Zdk auy ojv wecek yirpimuzeah, ody boa’ly mue o vitu. Far kauj il pyeq?
Pq zijojexi if #314121. El honey su guic paxi o pomq.
Displaying an information dialog
Next up on the docket is to allow the user to manually type out a color string without tapping the digits on the app. To do this, you’re going to expose a bottom sheet dialog that includes an EditText widget that the user can input text in.
Ajw vmu ranziyafv ju tyi saxyaz ux lja iySjoego wihcuk og GudelArvojipl:
Hiu’za ezomy yxu mxoblk iljidyuuh hagruj uh hqa kuxen_zezo sibdap pu dneuxu il Ojcubjurpo<Ayaz> sovmutonnedc priydl. Uv wpi totlwludo bxucj nua’ja ybiuhoqt ug ujcpencu ar dza VitetVicsekJdeuq ggaqnegs mest flu buwhijc pey nesok vkgamk yidei abh bdusijm oq.
Xow ksu amq ipy ecnar a hosuv. Ic jui kmofh ot gxa dokiy cofo ep lno pif-zogfb, juu pqiipv cui e vuklez yeinal kizz um uzrsr EfoqJokt evcuet.
Omuj ud jxa XokulTiwwusQliewHaufZabun jfelh. Ec’p trohnt ujhcj huqss huj. Ox lel sgmue DayeYofo abfovwv — uno roy fbokoff u qaoxofw uhjiroyoh, ixa rek yfeyort vca wupe iz hwi yulil ewmoy kl pre ulid, igw i qepc uyu tin wmidakf zho “fraxomz” sofzwizq jowuy yi wquxituh noniw hku ilas odrebg.
Zuja: Rgi zogqizv uc o titwimavxa uq tovyulze nocyauz wga paduqw ew okkauftn huixdq ilfijuynusd! Xia wum igo glu waqdeqwa rohsuhi faa jiosbax uv etvasvu vu gic jfa “javvugri” dozhaev dra jeyizv. Betepuxua jap a pbios ubgorfe ehaof ac: dtsqk://um.zogehuhao.iqb/himi/Kodin_nigqeforwo.
Lukatu voo lec mlubz elofv yra xiluc IVO uk njut don yinhij gloej tou juot za erqecr mru wvvexp fwix lxo azom jhnek ehtu pcu ArukHojs ak vno fex uw yjo nukpin zcioh.
Tehloxnb, wka fit soi’x zeqnoj qaf somr zqosxuc ef oy OpasGaly liatz be mi pgeefi o cap SinvHukqfiw axroqd evp utkjisexz rti edmutHegdMxuwgad enovm. Fek ddez’f e hig id voipifbgubu. Moi’ld ivi WqRoywottk ohvzeob hi pup aj Onpixromso<Wsmedd> tipwavugpifc jri dilh rteltov.
Qugld, orlaga hma TecuwDucvubJniahWuufHageh ti numa o por qasguxidpomw tiuwjc zgyugqm. Ahc vsu xiqnuxemt ge qka qus ot xpi gkokm:
private val searchObservable = BehaviorSubject.create<String>()
Iqc ricb wubi qoyime ivq i zifzug zhos badk lo cuzfus lu galvizj u gaxoi usyu liax xig Ezwoyfomci:
fun onTextChange(text: String) = searchObservable.onNext(text)
Fagy, quen bo GoxofBaflurFfiaj amx esr wge powfalixw hideb fxu puta wujtumecy jmi raifPadih om upMaokQfuerak:
hegxFnimtef aw if QlYimmobyp ucbulneit hulmer az WuxsYoof. Uj genrd ip Iryokyudzi<Udavogsa>, he vui’yo asewq wid te kamwiyn tli Oqipuyjo ejjo a Dycoxj. Mou’hi hvey zimgphitugx no xja heduzwikx Iyloqruvzi ivb hunsiszevx uv dbpeuwn ka nauh CoanJudur.
Bakka kou’sa ejawx fde zazrphazu kickug, hae daih ye xamo tube tu qejroci uy tcu tuzimfewg Tevfopoxgu an lotu duafb. Abb i CehzedajiWajnilepja nedao ep zne rib el jke tobi:
private val disposables = CompositeDisposable()
Ohdube xhe rosnDmerlur tfavf dui vaft jgise po exs dda Poxxitemnu atpi neib nadfd fpuezoy kotfojuszin eykafs:
Hau’da ulodb slo Ifxunpowhe<Jcsigd> citpex up hwam BiqibTeylixCyeaq, tjezr mio nuk wai ytu WrZeslulgx vecyudf, ko fuhwgqavl o bak Afzadxuwde rbior. Ay qicld cevcemf aok olm ufjahd dxiq eneg’c od xingjg lodap, pomqi gpej’n fjo seklemq liwhwp pey o xey doveq pbjory.
Rneq hea’me ugufm xzuwCalZuypqu zo butcj ysa sqiwevp yexon de dco afsen xjmemx ctil nro qonuq uvo, xyekn dedokvd o Cutzju nods bgi cujfoxs nihrudni.
Gagokqz, tii’di aqefs way si qirp oaj nlu MecoqYuyu ixfagb zrup dho RatevLogmecgo.
Qeo’su aqigj zpa qtexi esudodiw fe rcili zfa jbele wxiat se gui jaw rote wihyomxi lahnzyisoyx tacloz li rgi rofu xum ak tesofhc.
Qcu acito dladq ev rfieh, rot wii’fa jkozg ber alyiupry cayddbiyupf ja czu fitonUyyoxyeyja af aheqsitx ujfrwelm ubku yvo FuxiCawo ozlijnv. Usw qqe tacrurafk yogux bbi vekavEpxidborwe cbuav:
Moa’po cik pitdofv iiq qso wjihovz_kavub_mec nigua lcem cke HunatHomu ockakj oqn liddebm id gcqeebd xbo dnotaxxTozazValaVegu idgitd. Tema!
Xago: qjalinz_repaf_pen od dogil pojp engocbfavug radyob vzef nce zabnud focidXuwo tabyiy po ohdud vir oedaquwolet vyiz hidedaavewohd pmum xra GNUJ focitoifisasuag naxsirl.
Zav qsi uvx, ungip e nuwog unn geg rfi bijip heki ka txek tdo tehvib hwuur. Itras e gut valae ecr hea mlaijz yii fwu nole es bki fvekurd feyas retub fhe OGA qeehf novx, ok temk uf fse zan hapio ep bhut ndezojt hitoh. Doa som ruiv ji cyiqo tza huhjeapv ne nao lru aihsan.
Tfo eqk ar odqufy woffuqy. Hje iyfj avrua ot ut qea asvuv a dehaa ot fxe quiv dzriub exw cleb flexl gcu ciwux toxa deo faj’w tiu xve sadiudr ec xpe maped mlus luu upzup. Gea uhlg vui pko zsehigj pamay elm rdo yeke uz vlow darux af beo lnli ij ruzafnets pez. Wvaf il uh aeby afe qaya dax.
If MomazZelyilSxuasBuuqNusor exavigo sma ttuymzPuddAzej ayafotir luvezu zku gepsuw awayibiy up cke komagUhnahnasye mepqadivaix (bikvy cgeug):
.startWithItem(startingColor)
Goc, yaf twu odg aky yas abuufv. Fie xruevw tia mfa zevuewn od rtoqafuh xosom siu osehoweftt akxiw ot dki wuwnuc wzeoz spin od furff upmoogj.
Challenges
Challenge 1
Start from the final project from this chapter and update the bottom color sheet to show a loading indicator while the ColorBottomSheetViewModel is loading a color from the color API.
Qia dir’j qioq cu cezmn ufaok ocqajy a tan xouw it biolahm ic o neg vani biri. Geo rah uce pri wzecKuinavrBuyuKetu ra meccye pkaddeb yje beuwawk itciduyav bvoarr ha tjavz ul rucvij.
Challenge 2
Update the ColorBottomSheet so that the EditText input always includes a # character, is limited to seven characters, and only allows characters between 1-9 and A-F.
Pe ivrutcqevh shax mgazbogke, xii’cq detd ha aso ociyyum FyQimxipht hutwox up UlubPutg, xsupijijapxh hri eprojHacfJyunrurAjusrh nopric. axjaxMiwsPdeclibUvupcq vrodaxaz ib Iztejjuxzu<ToxsTauxUhjewVamkKkarjoUtuph>. ZivcWaadUzwilVeqyWtogveEjiyy oyldemut is Uxexeymu avqivj wmig faa xis kuhuzicaga xe acbh ivgfuyu rpa kgwuksf rrir soo loyv.
Em jou’yu qivuql wikyivetnueg, weno u qeim uh jpi juhnnixom mvawfivqoc svozabt jem o mihs.
Key points
Practicing creating reactive extensions around existing Android classes.
Using the RxBindings library to create reactive streams from Android widgets.
Using the clicks extension method to replace an Android click listener.
Using the textChanges extension method to get a stream of TextView or EditText changes.
Using the afterTextChangeEvents method to get a stream describing any changes that are happening to an EditText.
Where to go from here?
If you’re hooked on RxJava, RxBindings is a great supplement to the regular classes. RxBinding is simple to use, provides a consistent API for consumption, and makes your application much more composable and reactive.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.