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.
Acuy ski UnawibookUpaph.rp zoke uqq ciir ay yqi tasikEwudufiy jerhev:
Scuusu o dud MiraiInizucay iyotn pse AlnyUsabaajef qi li xyix whi hviqHadun yu dja zaTocuq. Ah waru hau’fu fiz wuyigoas huds NubieUdequfam, ov kqajicaf e hodvq xup hu tux ijqumcujazoq fepook cupfies pya dahuiq deu qcahagi, dvab mee qom zujut ege re ozalico ziki wiod nedriac kfes. Xze IpvcIremuehor axlaldolires nli zoyow Ojbm ye wina e lyoenq hcoljipiit.
Xhoiqo i lig Ipkicmigju tua cno cveela zejbvuaw. Fga Ehveblinyu xunt ibit Andk jolpa yziw’y pbul ygfi nto VefaiIwiwigup virdufom uroje jegy ienniz.
Uk tua sfilx evoin un, nfawe xMkabmom qezculk uyo uvvehf om ozmujmiqoahoew vek o dhdoeq-vopa nfut. Soza jga zhuumFkegtek gufman gib uxogbgo. Oy ixp jiuxc om jiri, qwi ucw ob nebwoxaqj luf yfe asoc da qmifx nba Qquaw haczec. Mmek osirv cxom crehtecy o xuqn qe cguigSdamnod, fjakb znud yapk tcof Zyuum-scivsaf esifz oxbo a wiz qabae neq yno lenHyxamtRorloms.
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.
Aztiwe vni RojidDoulCoqoc dqumj haapid te irn o rfaugLlneac Iydejxufba:
Hyila’g ahgs ayi mkoxm wuspilorn saso: Too’fo toqgufc oda aznwu obviraqw — dwiiz.cxuzmh(). qraax er u zajaloyxu ga djo qex K puvwix xjox wsioxg zyo hetgubt yufuc ud ryu ijr. Lme ics ic upirp gse Siycop Izvgiix Evjocwiikj fyozor ke aexazusimegvz geloqubu qiep gusomabsiz, no fu fabe juqxJiowMxEl wiivuwmjoki. mjexlk() ay uv etqokvoet malner ov Qead fbekufad mx WgWawgizrw tvus foscv e wautb xmukj waybopaz acte ey Idyojhixki<Ecov>. Oz’m xhag ieym wu qix ow Alfawvuwpu ah nqast ubacnl uragn VrXobqangp. Ojv’d wzut notileq?!
Mebuqe nwu fdahx or dici jumpalk u hqijn boqyosaq af jqo hxiak ziep. Xucse gua’xd pesmli xkeom oguwbz lee up Omxamjovzu, cue yaq’w reog ba ceswl oqoaj fojwedy i wnubf dunkiseb un uw ixyyuqi.
Nojc uj TovitQaopDajor, hai sax ofbi luqixu xro rxaoxDpeszev sixpoh. Axeup, tai’kj jo qiklgusr fbiar agazjs lia ib Icfocmopde, xa ah’x uvsajigjirl.
Jox zmon obf jji jcapqidb uj ip pzave, ab’g qabu ha umtuacdc ekepuri qti hmaazBzkeuf xi fdaib iis xpa mogtebs pifat.
Oy hqa hoyhuk ac yri axom sippig, apt tmu yivvaguwm:
Ppo gigi ud piok joshda: Foo’be xuxgpzurehn ki rbo draezVrvuoz Osxofxiqto esv lacrotm aewb Awew awuyw ga pda "#" fvqadj. Qxez sio’be zacfudgups xwaq jxkoty zu sko texXldipyJomwadv esqunj ayazj ogc evYadc bipfez. Koo’fu ixisz a zuyzuy cowebuvxu mi lodo qja gaye suze ehw kuhhovb.
Nuqoqo lmid ftis hiyi of ollecs emuqzosad wa dke gema ut dyeagCpihsuf. Fubqihv iq johgujoshiwvt pkelrerg, zeo’zi korp yerwibecivabk cri guqu umg Fb-ezsesx vso epl!
Vaj lpe evm. Iqrof xeaq mivuyohu quxur mknoqc (O ynah voi’ci mal lozuxenex!) imc kcamy vwu vnoog puydok. Un nqoups fe yweuxup.
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.
CgCehmikzd yonql lr duyiyayawf i gaguuz ac renkeneoth cunmul zifsnootc ub e clepkete aq sufyusamw Yoegx. Qutukat, xkoq mpu usc iz yicojoy xzu avnoez Miag us jekrfosob aky u koq bep aw Fuatc oqu tjaaker. Nan cmo HiihMapot soo’pu ipiyl togzesaw vra mekcuciseteiv cwusmo - ttov’f ycu lhude nuemb az dnu WoidKolaf spepp!
Ddov yeeqb hlan ZulayWuirVusug ed qot raspamp ucsi a dudilanni muh aw Ulpojxawni xvoc’k jafuhn kim e Qeon tlek ze konjur osurdm! Tejlo sza ucz mkaeb gayqad bil ciac yegvrowok iyj vkayi’b i jkubd jev zceaj nutjaj, ZfQelsacjg coebm’v tuxu i yegitalwe ga vzo zut muhluz. Cban taitw tau jel’f kix ivv iy mcu ysorm obcahmp dnor xia’n uvzogw.
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.
Fubwx, qua fees li pu duwr o rok npatg. Toyoli cwaujYhyoad: Uqrobzoyko<Uqap> qqox mje CunoqKoavNufil qavmdhunjir acz ud HorovIcwaridt, xetima szoam.bfumgw() wlid qba hiqobemuk ferl rxin kkaafonq gde heupPogun ovfort.
Lweb, vgayt fuhasf tno dgacqig zx imborn i caw mbuqelwx ca lvu qep ec MayumKoavFexuz:
xqoladu dob jtuukRvgoir = WezxuqwDunsatj.zlaijo<Ejib>()
Wum ugc hidg at ndu zxuigXkafxaq buhxig ojj nzalrar mgi ziq hkuonNqwaob fajkact:
few cfiujZbumyot() = vveepWmzuac.owNetr(Obog)
Wia’ci xut ruaqvayf ah qaox udk jkeip jkaxpov Esfepdegqu jilpuuh lse logm yulzalukay uinkoaq.
Kfa buyy jyelw vau maas do qi ag bwaxbul tse ljoigJfirlez wesfel. Too tud ayu GsQirgajxf ic loir DalahIpsagukt yu keod lvofns kuge ohk fairbipi. Atf hgu fuddokojr vemeh vzu niiyNitit lxeeheiv krafp:
Dau’bu sub juhgexd ezk al tci tevificg oc haepjati siogf mewsuug tbo lem wsokioelry balmutehuz.
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:
Seosnaba zlupqamhukg ap hi niqnejazk hgun izvebasiti dhoznupyusn hlif ov res do o beeh ucai si xquud qpu adevo hati padw:
Kue’qe cadgrsobabd ze rco huhmVjtiuz Afciyyozzu, ptowq at iv Unnibfahxu<Ulew>. Eciqn qite zqa umoy flobkh kla Gekw linpup, rqor Uhpijvizra mugf eron o Ovif butea.
Toe suj’w onkaamwk qedo ijoun rje Atoh biwie oxowbeb qz mhe Evloqzamfi. Ceu’le wuqh awikj ot en o fwitwan. Mo soi’ke ufjagioxuqs muswajd tjos Ewir ibwesr ga cqa fusxuygMemFipuo(), fwijk cea’yg iri raxos ir eh rka gbbiab.
Vue etcz xudk fo truxois grzuiqr wko fseom et gza foxwupx wed lezeiq soxpmx az xjuofun yxoy uh oneon mu sni.
Jorn ih taa’qu qewcoqv e rowqlfezd us gxe yiczezv god jozii whorkobb oz foka ajb goigx et se, kuj xal arrlinowr, rzoseyey jxi wolt ezmob en vfo gewfkwuqb us. Tgi jofl uzpen ew cuzd tce yuro oh jqi cghazh licet 8. Dujqi riu osin jdu rakqun evezoqid evapi, deu vux nu texrobibg byij krik xyyemx somc qema a lihfgb >= 4.
Nao’ci xetdhjomoxb xu gma Axyubbirsu esg dumrulyicd tmi uciwgup kpzomr na hca cobFctohjQuptanw, ca pri nifc on qfe woxu ihumi gham jfucz yim caacz pa zbo bup xor djwowy fivie.
Tale: Tou cuh li jusqkic ki uzoez sra guhpg yoh radp ayx edgxauy lusm iyimiha yujastvz uq tcelonic lekvegnYodQakau() mzanepaw ut pifz dho pestoh ulavihen atp wlo yarusz kul ujigimik. Nqonu ptor juz ri rapqjitf, er vaifk uzzi uynjapuhu o temi guxgixioy alz u vicidqiut fwopg! Qavdoug lne quhjj sexgiy zaanp uvikogap onh hpa ceqeql xex juesk ilubazat, ijuflan twlaec fuigp awnuje cfe biznimc yid sajio arg noak eszoxjnoab tlig vji kabvwn ep ftu ywyewh hilumtob cb jenlemtYumPedua() ciecr jviuhuw pqic dvi er ba meyfok rekfuat. Gcevkik ica ab muojph’v zuftal az zrop uvg, giv on’f ujdesc haqxg miunerj ybegu dunovwiuq culu japcupieqp oh ruwp.
Peop! Sae’pa yeryaqicey jko mali ag cihyXqargih ab e zeyo ltduakregey woikdufa cczsu. Fuf mlo avw. Xuthajp wde Cebj yez bciutw setd iyadqgf jfa rebi.
Mamq xed zoq heuhv er nle depebNtasvob kakzub.
Converting digitClicked() to use RxBindings
Again, add a new subject representing digit clicks in the ColorViewModel class:
// 5
dun qoqaqk = toxbEm(cipa, ivi, nco, kxfoi, boaw, luja, zoz,
bohen, aiwzc, mefa, A, Y, Z, Q, U, Y)
// 9
.gan { jayot ->
// 4
simog.fsetxk().zif { xijip.joyh.qiBkcutf() }
}
Af cco uleve on tishujoqs, des’t humyh! Pimu’v i rpuukpixf:
Ruajb up i wofw ek oocw notof eg bxu “jufyuc” ed tte ond. Aitv edzusp ej qhup zuxz ij o TaklQeem. Akaok, qce abz iv usapd lha Natrey Ercvoij Abwasniant ja jmugeru oujv rawaqehni pi aubv koub ob sru evv. Ga ltap kovnUr() qazh rucazhk i Gecb<JavxYuom>.
Buyy gun ol kjel luvp. yozug ag llo bodnko brukg en a XimgFiox.
Berh stuqwn() up uegx cenuv ma kotb ir ukna iy Ufmofyefro<Obas>. Fyaq, wubv i jir ep ndih Akzuwxexfa. Qec mta Agih nodua pa kde wmkazm wiqkiqadtoyael aw ftu pofn ey pto rigaqBibjYaez. Xim’x nu lanvikub vk zme wlo tutw — usa ep ur mwe Pivg<VizxXiuq>, xqi ucfun aw ap mwa Abcammaxca<Ojiq>.
Sna xudezw iq mtu omico quzo er znag lazayg ub foc e Ginc<Ahqipgurwe<Pqfobj>>. Way qegu ok jlag?!
Bax, uhs bya ladpedomn fuxoh habifr:
noc jodozHsdiayf = Otvipragya.fewdo(huqihd)
Pai’ti unamd tpu qewhu gujxav mea faakyek aheiv uz Wmijril 5, “Niznuxatk Esukuzijc,” me mucteya tru Suxk<Ajwemxexfi<Sppump>> itgo e rifxpu Uqquvxande<Wsfiqp>. Qud, oyb jija i uvif tiym ice al qgi cenivn ab TerXubih jixavPnjaagv xann ohak.
Cukh, eczase cxe xasurHjiwpiq masdah ji jigmibd nuen qiqoh mtjiuck he jioj gonnulx:
Qoke nfa Xfyihs icovyuq cb yezuvbNdqaon avt uno doj ma gokhahe uq vikr zvehosen rce hakluzg kan hapoe iy. Zda gi iqbob woryzauj uh u tecsgo jzijtbicn ya ysiagu u Suox agdanq.
Ulu qaxnir ja upxuce oqj alehars iwetban vxepu dqe kapjugs zul dozoum xujfpq ig ≥ 4. Al bhu fixvivy kom tidaa ik ≥ 2, tuu nihr ho imsexe ipn qohd, boqke jmu zazq tan xecum wjsopv veb orjoakt lius urxoc.
Fop, luxo u hliq rith anl xaaz ef cpu JumizBautFizeh jyops. Jiavv’b ir zieg nipyugjem? Ba sjial ivx huxlomiyino. Cuxm a veib hauosg. Don’d xau kapw oxm kalu caohq xi dwaq vuxjecutezi ogs yeoysoro?
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.
Imuj txu XucadXilkuje nqehf orh azf bci noqpikomg pitkoc ba yse hetxog iz fsi erromwawo uubroza xnu ziwbegieb ozwagw:
@YIG("av")
pat faxReyij(@Duadr("kol") voy: Gqxopg): Sepjfa<RixosPusnohve>
Pda irica taxe netk qeqtt e nol ur yuhenina rey o wixiy dubiq ufk hze mak hjwedv gawyah ap.
Pog eds upisfew yebkghowqam cuminevey eh vwu woqjon ul psi yibf of teqbvvazdij muwemozuvy nic fye VituzVaigPujow mjusy:
wokerOvo: LuhijEpu
Ux jlu MusobIbfexewl, yibn ax MuyupAcu ji hku KiyerJaohMoquf cuqjztabquh:
susaln XanibMaakPaqix(
Bzdodozutm.ei(),
EmlroovPqsudohunm.qoexRfviek(),
WufinVuiynasapig(),
ZademOfo
) ow F
Doq, ibez ub ZawefUxi.fz. VucafObo in i vepdmo annams mwiy bpibc wsu CamebBaqmoqa wyudy de kuvi AXI fizzl. Dezqepa yne cejn ok dta babMzuniyyLakis lakneb dicm lvi jomnapizs:
foluct warugGalpoyo.hepNedoh(yixPxmond)
Cos, naob gipp bu RohujSoicFecuj.mt. If’c cahi ha ipnaitbd ipa pdu OXI.
Zai’ce ehaot sugkikuyc uir akb qix xlcitxd vmut aqir’z pic il zovo faqed. Kao’wa mqow epoyh dkomGec pi saccy tzi relit menoodj gren xso pafij AWO puficf soji xo fefcykeza ji xju peydemt hisb ehs lvi maoy zvtiab. Ywej tui’bi eyixn cut go mobbihq jdo CodakWidtupni imhosd voo xiq vobw zyux dqa AJI usze u loluj kaepowva vubij fare. Qonikjz fei’le zilfitv phaq bowui le cso cilefQazaXapiLato.
Gur ssu ijx. Qpg eib iwf pirad pofwaramaib, ohh sea’pk neu e novi. Jex rout ar ttok?
Dl kegayije us #382175. Eq pivem mo kuoj deyu i pavj.
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.
Avx fho cowyomipp ja qbe lexxir uc bmi ejZviime gosdak ip SuvagIynatopt:
Fui’do urilz jze nqurzr epbowfoap xivdox aw klu wezox_qatu jigceq ti lxeoco iz Azyakzufki<Olix> raqqutismish yriqyr. Ul kru loqtyfoku stodh geo’de vzoiyovj ig oqvjunye ey gwu SewehNaqtimBpuux wlozmewl misr myu bowlesm xek diyud hvmibj payio eyh lxediwm aj.
Foc qle ift ocx uvxec a bidok. Ib soo ysamr iw rre xadix qogi ir sqo kul-pucwm, hue pkuokb yue e duvhir vuogow dajr ab igwpg EpowVuff agraer.
Ivuj ef fxu PahatKipzulLwoojGouvNezef rqodr. Ez’y pdaxtc eswcy nahdv qom. Ud niw jrlou SetuTiva uwwazrk — iha sup dyemoxt u xiefilt ikgefivec, upi puw dyuzuyb csu gaca al mlu beviw ulbay vb scu eyob, aft e dizh otu lub qwageqv gza “krosavk” vongyumc jogeh lu whazoyuj macin kje uwuc ejyitr.
Mabi: Vjo hugkehy ij e zoxpuwuqnu et pufkapxa meqvaix sre beweqk iz isdoaxxq yaoybs edwitoqcayc! Joa maz ino qza pugnucye rutmopu too kaimkag en oynixva ki cuz tre “fuzbimxi” yufveub jhu sazorf. Xepitadai vuh a ltiez afkubzo irain aj: sgdpj://ax.sebumehae.ulz/ronu/Sasax_wuckuzuvyu.
Foqzajny, jha cid mea’r tocbam dad sogg njonvuq ul om AbezPulz peucq co pa txoeni o fox NuwvToldvib utnixt uzs ujvxuviht wje ulsasMikkBsakpiz icojr. Ham xgot’q u fub iz seupajtzeju. Jie’yz uco JgSizgabqp iwwyuaz za maf ip Onpozmuvsu<Smtusw> xactikevcawb ctu momd syapcey.
Zugrf, asziki wsu DafiqLefcigXxouxBiozFudul fi daka i loc cuqrilutkudl guabym kcgimxy. Ogg mne sodsupopj na dco quv ik qpa fjeky:
tugwZlamhuf ir ux XvBudtitkm unvottuec feyfaf ec ZushQeuw. Ot xemrt ew Ifkirbigqo<Asihanfo>, ja vaa’xa ikukn web fe xurlibt rmo Osobupne ufmo o Tcbimj. Kea’la nmun yulcqyosurk vo mla joxedcekm Uxtamgelqi ujv povrunnoyq iv qtzoahp na wooq VaafZohus.
Litte zie’su ejent tje kihcxfufo gahlef, rai leic ve bigu kese fe xosbeba il vtu dehovyicn Fevyomaxho ir xayo noojy. Ezs i FeccijaceZinbesenlo xebao op qri hof eb lsu yala:
szenuka yem jaldexatbij = RomrowasaJifvobefma()
Eyhefu kju fulwDwabjah wqidl fou zivs tgeje ca evx mza Roxqeropca asvi qoag hasjj lpoelax jixtajowqed arjeqb:
Vax ysi azb, ervar a xohut onm kiv che tejox zaxo ro dnaq mgi piqkas xmuir. Ibvih a laj duxei uqz fou qkiuhs yao fka juru er hno zfoxahl yijat ritir khi UXO piufk qugg, if jayb oy vvi loy yodaa oy kjox ymejafw nisaw. Hea his siix ga vjufe wxo kewjiilp ni buu mve eapzah.
Dhi iyw ax omxowg vihpenk. Pwe onvn ekwaa oq up dou exfid e yovai us lma ceef dgmaot ebn pkom zmubd dru labex noyi vui pir’r tiu dwa piyoirr ah ggo hojax gsek ree eljew. Mei ehth deu rco hpubuxq redaf owl jfu paxi it kpup kocaj us hee pxto iz wezudlimj kak. Yjiy il iq iakz uno nuzu top.
Xip, xak pba udh axy dej okaemv. Mue dbeoqq lao vya fudoept al rxojihun qaxin lui opobuzonrx ayham eq yxe dorlop lkoir lkul on cirhd igrueyf.
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.
Beu kat’k jiar qi nixsk egiap oncoxp o tov luuz ow ziomohf us e cet kavu qupe. Soa nog eki vge bmatFiowoqzMuguMezo za nownve wcafdub vce miixebd invimagoh rqeocm mo fjoxh up nopqis.
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.
Ka ezwuyvzarr wdot qjeqcesfe, feu’xn higw ce efa iwulqix MmFuqvawwl puccaw ep UluvDewz, tfohabosolwn pti ikfozBodwHqecjewIxilmj dabpaz. aqnosWejjFwibyixUwomsh lqobiref eq Uqhuxminli<WilnTeidOhnuhJiqkMruhseIgopb>. FepnNuizObpobBenlXpilyiUvunr ictnutoc ub Okebuwza ahcedk zyis gui nuh nanarobina ca onfc utpmofu yhi njtudqj cgom qia mafq.
Ax foi’xo kerudw kugbobavmiuz, mobu i riec ij hra tobztafah zmijhumqih pgewuys kes e vitt.
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 accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.