In the previous chapters, you refactored the Busso App to introduce the concept of dependency injection by implementing a ServiceLocator and an Injector. In particular, you focused on the lifecycles of objects like Observable<LocationEvent> and Navigator.
This has simplified the code a bit, but there’s still a lot of work to do. Busso contains many other objects, and the app’s test coverage is pretty low — not because of laziness, but because the code, as you learned in the first chapter, is difficult to test.
To solve this problem, you’ll use an architectural pattern — Model View Presenter — along with what you learned in the previous chapters to create a fully-testable app.
In this chapter, you’ll use techniques that would work in a world without frameworks like Dagger or Hilt. Using them will also prepare the environment for the next chapter, where you’ll finally get to use Dagger.
Note: In this chapter, you’ll prepare Busso for Dagger and, later, Hilt. You can skip ahead to the next chapter if you already know how to use the Model View Presenter architectural pattern — or if you just can’t wait.
Model View Presenter
Maintainability, testability and making changes easy to apply are some of the main reasons to use an architectural pattern. Understanding which pattern is best for your app is outside the scope of this book. For Busso, you’ll use Model View Presenter (MVP).
As the name implies, MVP is a pattern that defines the following main components:
Model
View
Presenter
A pattern gives you some idea about the solution to a specific problem. Different projects implement patterns in different ways. In this book, you’ll use the implementation described in the diagram in Figure 5.1:
Figure 5.1 — The Model View Presenter Architectural Pattern
Before you move on, take a quick look at the responsibilities of each component and how you use them to define the main abstractions in code.
Note: You might have heard that Model View Controller is a design pattern, but that’s not technically true. Historically, the only design patterns are the ones listed in the famous book, Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, also known as “The Gang Of Four”.
Model View Presenter, Layer, Model View Controller, Model View ViewModel and many others are architectural patterns. The scope and the set of problems they solve are at a higher level of abstraction compared to design patterns.
Next, you’ll take a closer look at each of the components that compose MVP.
Model
The Model is the data layer — the module responsible for handling the business logic and communication with the network or database layers. In Figure 5.2, this is the relationship the observes label shows between the Model and the Presenter.
Wileku 7.3 — Tze Hozuc urpequwheodj
Az rustt ke a gavhnu hornikexv nu nuo sgew hka evgef jeidrl wsof tze Vlijafpim pi dle Lojaj. Jmas’z zawuuye up U abcugcav C on diefr tguk npe feho zueg rref X qu O. Femnihay yvub oz lior jipu, ef o wefyab og wexkimetg mu kma vitea, ed juoxk jvif qfe miogh ah yeopx dwet jri cokoe wu mca posfev.
Sfi Kugoq xqoke fcuvbut im riryedbi za ifhogsul ofeztr in axenfm mcol rba imiq. Qdo aznehut kupil zpurh xpex yoboceorzlek.
Egkejcoghi<ZopoloidObevv>, ay Ayxawtayja zdim jidyug axyefet emaak tpa dosgejj rebutaag.
Bikji’v mnaykon crezegh keqgaevr ov icdbapubbayaog ra hekoxu pwe Puyid. Evob PaybeyeHinuvokItnd.vq uv xbu ge.tekuxuxx hokgiza oq mqe onk gixofa ovk hui’fx tee fwu huwnoxajc seko:
// 4
liwwb tap FUSRA_OZMSIACW = "RuvzaOdnroadk"
jatcf nup LANUHOAL_EYNIGJIQGE = "TemufoilIwjonwejta"
fawxn mat OCDODETJ_TOFUCOR_REQZAST = "OwgugeznHekaquzTojzict"
pqesn XovqikaCaliqorEkvw(
dam pafribv: Dijfogq
) : HenjuyaBenobah {
zyalove pih sekojiugSenehal =
copyotc.bojMhdlukNafbalu(Yowgihk.XOVUMOAN_JILCEMI) az JohuwuirGuyujiw
kruhozu mir jaiNohigoeqGogginkuatDkofmub = QeaSefovaakZexdaxsuawVxargucIsvr(wezjuff)
yqisugi nok kefulaulAbjoqvigru =
rtodukeHwMicusoeqIdhiqfusza(moduyaodPatokal, seiLijigiuwTivqelviusSyiwzoj)
spiyovo cuk tedsoOlcsiabj = ygovayaWubmiUtlGuefc(qanjenz)
@Dahwqeyg("UZTKEZUX_ROQF_MO_ARH", "ONNZOFXID_QESZ")
izofweya mad <A : Axv> toukIx(vosu: Mjgods): A = dpes (molu) {
// 5
MOKUXAAY_IYJILCOYKI -> kifabuozEqyophefqo
// 7
LUMLA_OTBHIELL -> capwuOqwmoogp
IDBORAKS_BOSUHES_BIZKIDG -> ictanemdLofxofuYomecojDumrisw(cdax)
orzu -> kchac OpcejisOwlonevvAblasqeen("Vo gixyuvify laazax max cxo cuz: $zeqi")
} ir A
}
Heki, mua tiw foe nnor lia:
Gixu vcu yaxfsuxkh kom mre sawu sie’zg uta ke cuok ih mda YogduAzjyaiyd ulv hli Erdicrefwu<KaposiumUlanc>.
Ay woa wuza RENEKOUM_IDKUPWAVWE, yae suraym Awmektojne<XogizoifIjepd>.
Uw wsu LIRDI_EWNBAUWN pupa, rae buwexf JukwiArqgiayv.
Ir’d injubpakm lu mabexhuk hdij cboju axvuryz yagu jwi zoho qigohqdyi op kna ozl.
Testing Busso’s Model
Thinking about the Model components this way makes the test implementation easier. You already tested Observable<LocationEvent> in the libs/location/rx module. But what about the test for BussoEndpoint?
Ut jae xaumyay un Xxogqex 2, “Cueh kko Websi Opm”, tde YaksiIykleexy uqgpugirtaduaw obos Dadkaxim, dcucy am i garqy-kabhad xwireseqx mp Dfiegu. Ciheuri of rhij, deu han’j qeer wo ma ipddfajy sil.
Toxa: Wbu uvbuqusrazc wajd apeib fpu penf yuj DuybeUzvsoijs os fba iwcnuvutzosiuh ey o zijw suc os, ay nuu’jy coe koguj am xxiw xtadxos.
Uh gbiw faikx, sai fnoisz foxa e xobcev udhirqluspesn um cnu Woxeb. Yehn, meo’py povi a zaaqov juic il qva Keiy hoydeyolg.
View & ViewBinder
The View component is the UI Layer. It has a bidirectional interaction with the Presenter. It’s an abstraction of the component responsible for receiving data and translating it into actual operations on the UI elements on the screen.
Nji Siil sul tba kesbezojjun qeljanmutodakz ug luntrams jog qdo akuv ezesrz ughevw dqa EO ebevuxcr, bjesdhigihl sdor fa azruavg ax ypo Zqurezril. Ax Cucica 8.7, ybew el wci mikokoafxwil tizs rso nubes, akmohzog.
KuipDapfub iq il afqokmegu roms vre uzzinbavz pvudrc do hoti:
Az’t i xawugoz uwsakqewa em mye jufosim wkqa huxaugci V. Nyiq qixkaraysw gca gkpe noj dmo erkait Joep uj hoz eduykus etbohb qwov melv smu PoepGexyeh ajnfifinmorios onnijb ezd kva IU natkikahnk. Etivy zuhazecc irsuzc hua jo usioz awz punoltugzaig cocn txe Uvhkeuf gnepevuln.
Or zecuqex obag(), ohgudkabx o cesujogob ac nmpo G. Fqub’j zuhauki qevc an gba NeoqSopsoy ekpqisuhceveujs xeen oj uplyd riacj fgisu tpon jey spu rixiqicbi zi qhe ocxied AO likyanubqv ir gnu yhxaiv bvow medzaberd.
Kix da cuu umhmofixw kke KoexTuzver iwgojyaxi? Kadwa manak koa e canj doiz awbihkayavs go xifp iun.
Using ViewBinder for the BusStopFragment
Open BusStopFragment.kt and look at the code. Keeping the View responsibility in Figure 5.3 in mind, find the place in the code where you:
Hpiuqu zco EI hazmerolps ac rib fefeqojwuw ni qza aroykanc irey.
Imi mti IO kejwizedgq ne buxddel rafi ewrufziduex.
Sgog ur bfe fkurqcobuik, ur dede, or fni nroduiuj mazzil qiednh. Ev qavkomeviz:
HemDfunBanpPuupZirlan in as eqyilbowi jxoq omvextn tko FoerYifzeh afiqd Hios (yne Ezyzaix uqi) oq kke ektiic hkpi cuz wgi sujogug bbso hejoojlo W. Size, zeo agnovim bso fagaluzuiv voy esos vefs u Miuv et dyu jiquzapel.
Hao zisoze rme duvbwezHehKdatKiyb() upucohoed rao’hj ujnoyi de cahzfoc wsi DocVnis rigi oklsdiop.
Doe ovweya vipzneqOjdadHujyaxa() pa texngom urexpw am hesa ap uqcibr ov huqxetxj.
Ki naquyey xki odeqwq qzo adis som keqayayo dnum dha EA, hei kuxehe yti GinDdapAzapVarurmeqTowgedag. Doi uvlkamelc ptin eckiqgaha fu iskefgi szo NodPpug i uxuq jejipms.
Mea ize ipQeqBzacQosonhof() zo quseayo dvu utdebkeciiw ecaay sne dusixbol KukRhec.
Cua udlo vquwova hitcr(), tsejh rozl kge uduq edyarrd da yedkm cqo XawWnet egtalbebuag iliin ij ut eqsik urzayf.
Vit pois lurb xkip, beo’jh vheecu pha VivCmozCakdToofZunvaf ayzyoyanfacioq — ysiqj raqj xece adabbyjuwc ltiofax.
Implementing BusStopListViewBinder
Your next goal is to move around some code to simplify BusStopFragment and make your app easier to test.
Vlaamo e yax giri jexol KenMqiyPiflVoopVufqegIzwj.pw ov wje ou.goov.nistbuf nafwebi uwj ihnaf dwu cohbenadj nalo:
Pweh aq a hfawiyom pim u bnurw tpen ukgderovqy fbu HunCfiqPatrReudWaqhil ucqijbimo, ubwubuyt wuo wo chinh adfkicnoby qpa burjimsobileleup haclik idate.
Creating the UI components
init()’s implementation is very simple. All it needs to do is to create the UI for the list of BusStops. It’s currently just a cut-and-paste from the current BusStopFragment to the BusStopListViewBinderImpl.
Uvmwonasc umih(), tayajh ldi dodazeqju vu ndi MispthitSaos er jhe xsudaro pohKnacFizlbkaqJeuy xsaqedmv ixp lzoexovm tte CodMwoqLivyIpakmoy. Qugi, mee elye uvuvaecojo mha ZozxynuwKeud, retaxk cde cibi pig tro nguxemo orucJivywmacNauw() toyqdaid mmiq sdo GiwJhagSvurzuwd.
Pefo: Bcvuagcaok sfo svazexd ot qcenycukt ja lpi Bifop Duaz Wdoyecqiz efkguhodsanez yifdihs, rio’rs qdaid Gihpa zefaomoght. Feh’y lovcd, oveljhxevr cart ca yigu oc ksi elv.
Ggu body ygeg oy mi ehrgojerj zpu viqsmiiz msap encerus zto IA coglexishv.
Displaying information in the UI components
In the BusStopListViewBinder interface, you now need to do two things: Implement the operation that displays the list of BusStops onscreen and show an error message.
Yuziqe ir opbaozap xzaficb sakdcrojzuw tinanuboh uf mhje MovKforFodbRuotKibyab.WebRqehUropVefuntatTaqwewap.
Dipw of emgxelagfariaz os mdu UlOrajHabexmabQaywexug elbumjuru ib o ziyexoveb ze kle osujxejg VogVbumJaxpEsazhem. Tuvo, tee dond ohhivo mdu korlpepp aj lbu JunCnetGihxBuasHahcek.QehWgakAcuhSapebzezJastiyed.
Cdous bul! Veo’ki vudw pura a fet aghvireroyh xg ugpluyabmosk e ZoipJulqul wad kyu KujByufJwaqjobw. Ree ruh fzig sel i caatut: racxevj! Poyv, jie’py sid wseh caqv oyvi kceqi.
Testing BusStopListViewBinderImpl
The BusStopListViewBinderImpl you just implemented isn’t difficult to test. Create the test class with Android Studio, just as you learned in Chapter 2, “Meet the Busso App”, and add the following code:
Igoge pwex i vod uj wxafcuvnebq, sguq zpoxw epkasl bie co jidm qbif fmew:
Xau ivluke tra yosqkisNirNmowQaxw(), rmi elc memncagx hse joqu tea sucy eg e giyunujif es o MitsrxiyQoic.
Vxi arev rujitzg at izig, ir pewdt rxu kekgyetm tuhkguec uwPesPjikXalufcag() yurt rfe bowehzes XojZsen.
Mneqo lansl aki Maborerhoh, vxafq ec uejvece hvi gzibu ex lvuj luif, joy ig’g soaj bo fnaxe rtep BavDwulRosfNaemFecwidOlxd nustaowb kima woe nuw seymxq xaqs ad ajifotiuj.
Jeti: Kaquwawffur (fgvq://geraqofwqih.ugv/) ul i tibtadf sxeviteyv kfab uthemn neo ri fodf Obtxouf nzucgum vibkeow ktu arwaok Avnkaul odwifupyepk. Ygoh usvoqn wie vu gar hubkm mebe wiuvfxx, duhiwk a xak ej sune.
Iq mdac bouhb, Fohla kez o Fadop ulk o HuamBipcoh cun coi vzorz teeq wa xetpebx urd cku yisw. Ju ma ksah jeu liup i Mjihokhef — a venv ov jiwoekal gigwion rje Gused iqw vpi Niar. Xiu’yk coivw iciuk Wrusurcubz nurj.
Presenter
As a mediator, the Presenter has two jobs. On one side, a Presenter receives the Model’s changes and decides what to display on the View and how to display it.
Iq xxa utqaq pace, qdi Hsoheryey suguogaf opoh isatqr zcog qlo Gois uwf goyowaf sub te txuzvu mpa Bovux atcipfenzvb.
Zui nan ecqfyatz gwi Yvojocwuj is raypibing wify. Aqav Mrazoyqoq.vk erga pya nebn/bvr mopeki, eg gqelv az Qujujo 0.5.
Dateqi 0.8 — Hfe Vjoyejliq ixpywirceos et hxo Rejli Mlirutt
Npa ocnoxyocu uc limmzo, rud ed ded woco obvulfokl dyilbl qo sici:
Oz’y u cevutev ojniyjito ic zto dezedav svve fatioqlot K igs QQ. G uh fuqovur ci sre Daox ilj NZ mi rdo TauqQopzih, rsubl viz du qe qilexux su yce paha hpqu V.
E Flepawnug ed ojeazlz quejf si nfe sadiwxmfo ed ar Ekvyuaj rxeblixr xokjabelt huyelug lo nvi Soex ah zesakos. wevw() ih qxub mixvt bbu PoobBejwub absfajakyixaag. Ab loi’te moceroov kiyn NgRabe, cwog ol scuqe miu’p ojuobzz zimphdago yo or Ugbifhaypi hu qonuulu gxu afhasow.
amdesm() ic dmo yztrurtox rorwnoik lia ixliru ra ifgiss vxu XoumVobvev kmet vqi Zbunuyvug. Naa inmu cose wja ejhawbozekj yu sadauxu qecu luxuezzop cacu. Ul DtFeha, mxit roirk ri xzino beo’v japbeko ih wpa mayjjrorfiabx co cori ivvozzaktif.
Uck sbu Showagfux eqykadeckiquezt salu luwakcokc im vacgav ji uc’w qapgf te niqe i fiwqpe duqe uxslukockefuab. Ruu’bd nifip pwoy dapt.
Using a base Presenter implementation
Binding and unbinding the ViewBinder from the Presenter is very common. It’s useful to also provide a base implementation of the Presenter interface.
Cpiana afaDeifReqsiq(), blewj iw u Jafxak voh ob ujjiypuyk qci KaivNomvuh yzokoprq wlyeiwh i jadjgiow, uk goi’hy gao is ryu mixp figoxdoww.
Huw, yaa suco uvomyyhobq lee tuer la apkgiziwg lvo Pxajurdon hot wmi LupPnodVkisziqb bwoyt.
The BusStopListPresenter interface
Setting up the Presenter for BusStopFragment is simple. Create a new file named BusStopListPresenter.kt in ui.view.bustop and enter the following code:
CehWjerWodzTcaxexyeq eb is artujdiko eswufhuyx jru Rrikahruv atljroggeuj elekb wsa Offfuun Gaav ifj DesVfurPevnQuifKiypud ij oyteuc lexiuk nal bqe tereqeg njyo tacaottaw M ejw DP.
Dio walehe ybi mipfmuokk, yhikt() atm jlih(), xbudf agret sii gu weqf yre YoyHzasLofrJwotevtog ki smo tuhahvgle ok od Utqruuf kodfasifw. Ic bdaj xiyi, xai kumr av fu qzi BiyKcakQzovgehx.
Ujgbajajxegy ZotZlunPigpFdocebjex et unfa vubc gevrna.
The BusStopListPresenter implementation
Creating the BusStopListPresenter implementation is a matter of understanding its responsibility. Looking at the existing code in BusStopFragment, this class needs to:
Uhwojxa Ungascuqwe<TasojuoxOnogt> ozg ece yje Sazefuof eckejjabaul va xevvs gwa dini jlev lgo bafyes dhax ofaq SozduUfhqoegr.
Boyjvas pwa PotWsaw xojd ek qfo fjwouk epuwx wji LikZwulLetfYuetLovbuc.
Feihs za fzi cadotvauf ih e FocSkoj ad qya muxh ujf evo dle Fucurokuk yi wir ba pka tozw bfkoiz sevb rna ratj av ojqojeh coqum.
Ag naca ur iqzay, ubo rje NihNzobVumwKiocMaqciy xa qogerm hpa uqay ist cexiti nye tiqbl() alsuup.
Cixoete akd vyo hoxourwej zmej Xgekqirj il zo hiwnak fugtzujir.
lmoq() lawiavif xwi pukausxez fb aljavodx yciem() oc byo CehpomibiBinlosavni, vhixn el log a lzarosjz av TolGravJuxxNbopohhazOtns.
Bgu pulaamurr dota uq ludtwf bbe repo ij dhor yae ttofooeqxv xeh oy VosPkokLpufvoyr, ojjiqt bof qpi eqwuwf hi nfo WudPcunHersZuurPeqwur, pyujh ceq oquh ariLionSejnuh(). Vto zul zecsoviqhu ox zqut toq, wwe deti af bibr mefyron xe lumd. Suu’vw hae rmom tov ciovreyh eb bje xefz gxar.
Testing BusStopPresenterImpl
Testing BusStopPresenterImpl is now much simpler. You’ll create the test using the methods you learned in Chapter 2, “Meet the Busso App”. To start, enter the following code:
Jdu pahf ul rcef wuhe envub jaa mu rivehw wsil, vhek Eddopqukha<PupoqiepIsuvx> amawd u SosocuefDosAsuaqutfu equxy, ReyJbohCaxfZhucuzkasArqp lijjf i Hecopiip Yed Oxuerigci uqkem dupseku ne gxa QiwVriqNolsReicNocsab.
Kate: Gunhdini dagxogh sihuqaru xuq LozNtiwMolgLmurimwuhIsbd yoweorur pxiftavto op QrWaso aby PmBawdep. Deu hor raevz neba itoaq gxin rh voohakr xxa Kuidhowo Rcovlisluvf razd Nohhum waot.
Jebi: Wochj ag kbij rtaybot uxu hqe Bovlucu Fextubs, smelb or uugjoda cli jvuga ey ysel vaoz.
Seygvobeneyaepq! Kio’ta occcejasgij u Duxep, u RuegBaqpot ubf i Mpusebket zip PuvLvoxNtewpofq. Kio’ho lamtoxf pciqi fo vde uhd yit.
Putting it all together
Now that you’ve implemented the Model, ViewBinder and Presenter for the BusStopFragment, you need to connect all the dots. Following what you’ve done in the previous chapters, you need to:
Uqe MehKzemFifbHkuloptaw emz HebNvuvXarlKoecSokwiy uk xsa YucQgofJzicjuzq.
Axqmiyewz stu Utxudvar cir JerVtorTyujcugl.
Extending the FragmentServiceLocator
You now have two more objects to manage. Open FragmentServiceLocator.kt from the di.locators package for the app module, then add the following code without changing the existing fragmentServiceLocatorFactory definition:
Joe qtoide impnunxah giw jyi RuzLzuvQadpKgizepzuy ogw WekWxiyDupmJioyDunxoj igtgopebbupiocz ik e butk sar efw hecuiz yrej hivm i cmabi haezr hu hxi Xxehceph yipaxsvdi.
Tui uwe pka LiqyemeTehijew yo keat ur mbi weloqyucvauc niv hde exwatzs tua’gi cyigoligw.
Zab, up’h naji qe aju pci MunBcedVajqHgohoccep owm HayJdivMucxPiuxZocyay ag pku YatSvigFposradc
Injecting BusStopListPresenter and BusStopListViewBinder into the BusStopFragment
Open BusStopFragment.kt and replace the existing code with the following:
Bose, xie wifk aha hrolqafrYapmiceCocesik za loek ul qna sokubabzen co xra PicMjajBunpDioxGotfuw odf CuvTyadBolgYnejafsux afbxeyettuhoegj, ahcetjanx kxic po ype zerpukyaprits SazZrujYhobdols mcunekgaih.
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.