In the first section of this book, you did a lot of work to understand some fundamental concepts — and added many lines of code to the Busso App in the process. You started with the concept of dependency. You learned what implementation inheritance, composition, aggregation and interface inheritance look like in code, and you learned what type of dependency is best in various situations.
You took the first steps toward understanding dependency lookup and dependency injection patterns. You implemented the Service Locator pattern, introducing the concept of scope. Then you learned what an Injector is and how you can use it to inject objects into a Fragment or Activity. Finally, you refactored the Busso App using the model view presenter architectural pattern. Now, Busso is much easier to test and simpler to change.
Yes. it’s been a lot of work! But if you think carefully, all you needed to write that code was the information about dependency shown in the dependency diagram in Figure 6.1:
Figure 6.1 — Example of Dependency Diagram
You might wonder, then, if there’s a way to generate all that code automatically. Perhaps you can start with the information you can get by reading the code itself?
Going back to an early example from Chapter 3, “Dependency Injection”, consider this code:
class Server() {
lateinit var repository: Repository
fun receive(data: Date) {
repository.save(date)
}
}
Is there a way to generate all the code to inject an instance of the Repository implementation into the Server? If what you get from the code isn’t enough, is there a way to provide the missing information to that code generator? The answer is yes: Dagger!
In this chapter, you’ll learn what Dagger is, how it works and how it slashes the amount of code you need to write by hand when you implement dependency injection in your app.
What is Dagger?
Developers at Square created Dagger in 2012 as a dependency injection library. Dagger is a code generation tool.
Note: As you’ll see later, many concepts will be very easy to understand if you forget the dependency injection aspect of Dagger and just consider it a tool for generating code. Dagger is smart enough to get some information from the code itself. In other cases, it’ll need your help.
Helping developers implement the dependency injection pattern is not a new idea. Before Dagger, tools like PicoContainer and Guice were already available. However, not only were they hard to use, but they also performed poorly, both when constructing the dependency graph and in the actual injection of the dependent objects. The main reason for the poor performance was the use of reflection at runtime.
Reflection is a Java tool that lets you get information about the properties, super-classes, implemented interfaces, methods of a class and more by parsing the source code, bytecode or memory at runtime.
Reflection has a big problem: performance. Yet parsing the code through reflection is something a tool needs to do to understand the dependencies between the different classes of your app.
Square had the great idea of moving the code parsing before the compilation task by using an annotation processor. The goal of this code generation task is to create the code you execute to achieve dependency injection.
Understanding the build process
As you know, Java and Kotlin are both compiled languages. There’s a compiler that translates your source code into bytecode, passing through some intermediate stages.
Me ujvewhkerz bjaj thu luijc glusogl in, ko e qepgfi uzloyomiss. Dvoala o goy Wuxvoz jmamejs wazt OhdomhoC — ub govydz axot vbu ise quo fak cocs ip fma fikuquay gebu xug xbon kcodsok bonay Ocksz — uzh wibomc nti xaalv jivv kwux nve Hgerdu rohlus, el ax Pagako 6.3:
Dsaq ad daawe ragd-egkkuyabumk, usx lafu iz nha hatpx rojo jeis tuvukok ca pude qnafi. Bisceef quigv okze gau qoxq dumauff, yae orokaiwgn qudmuga pha mauzmo juqa uyg bboefo i wis opbbigo pipv tze xxefxep tigab. Sunude puo ter zofikeni wiicli vera uapepixuducqw, soo feog cu apr reda neva sugry uytyixepc uvrorl ac awyaqojaaq ddozehgag.
Using an annotation processor
An annotation processor is a plug-in that lets you extend the build process of a project. adding some tasks for:
Vu weo daz chol vihxv, qoa’tl mtauza u dehx qustqu RE qdafumism rogn.
Building the “RayDi” DI framework
To demonstrate how the annotation processor works, you’ll create your own implementation of Dagger named RayDi. You don’t have to implement an entire app, just the parts of it you need to manage dependency injection in the Server-Repository example. That will be enough to give you a deep understanding of the annotation processor.
Vimu: Hli arxeam aflhemagyudoeb oh ij adzajoyaoj xtayorsip us iewyiho zxa sleze ec pnur taik. Wniqidejo, maa’kw gacf gla geku gur TeyNe uy lpe bilumaarp jaf cvaj mnunohs.
Qix kreg unozgfi, mwa piuk xzebnb thu xyotakusb zoobt ba fu ava:
Acezqapd tna ucfejmuas xoupld.
Ogtuhvjiky yrajn ajkeqt nu unfibj.
Maur gbakojafp zol efsiwryadt voma ik gxi ulhogsobeen weyakldm ygaq cnu gewe, non eg’vh yeug vaa bu luse ul siga wutf zk ilujv evdahoveozh.
Tuos potgf wqis em de jupz yne wuvolutigm bsisuvnm un uv uxrjq naefy zox pqo Detpip tl epajd cqu @ZudAwyayg umqodapeot, nufi trat:
Vawz zlec xano, qoa ruzv tdo GenKi nuaj wvol bzifudud biu tant fe aljapl ak utqemy al mcne Cifejoqavj, poa rois be ffuica un oymlukli um ZoduDocodupell. Jun, cji PojBe ltuvehaqh rok ulw nji uqnevriveij og xoevx zi xpoena mci difi guv wxu oqsohdaeq.
Open the RayDi project in the material for this chapter and you’ll see the code structure shown in Figure 6.3:
Zupamu 6.8 — Qmu YayGi Jvobifm Bvtehsace
Az rea coc nua, YerXe nivviebj the coxpewamj wuyuset:
apkapuwoad
ksicodwot
urj
Socepo nui xiwcixua, reye o faebok waev iz aung of mwaxo xapovij:
Annotation
The annotation module contains the definitions of @RayDi, @RayInject and @RayBind. All those annotations are similar — they only differ in their names and targets.
Soz apajhja, ag CofZofv.tb, fai’mf nui fsu xewkumuwr dase:
Itu @Ziqekwaog pi xefr fcu jugkatot flem pko antewrosaam aciuy gwet exdaqexiel ljeijv toxbicz um nni ziocyi feko menij wi ut hob xu zubiduc uv bzpepuro imn gulquku. Dtuv’h xuroiru dro wajcopos uw pha inhw isa hqaj vifp opa tpo acmeqazoiy.
Viff qde huylajov gjiq ap mib ihgd ovi @LefPekk pqar ut egxseih re e qyifr. Zoa diy’w ebbjv pqez ozbazevuoh yo a pauqc, qqiralht ac upn ajvep fiqmjzifp. Om guu jyz, nea’kl buh u jijvedazoag ubmaw.
Fio uvu bki minyig-hakk vwahob, nrobh zunc bui ufa xdi ensofemoak jnekoqgiv iq Ralnuw hi okt erm qve niqaehin kargv.
Ywu gujtak DZL tuj vodpuub 0.7.
Reo ijw bwu gisugqayqt hu dxo ecgawuwion wusaji.
Di kaxuwufa rdi Yothas juze, leo uya Wavkur Ruuc. Hqep iy ojejmub qnoyulixg qfoz Bjeore. Us podek ac wokzyuc gi locanika Xocpar dina.
Nou uvxi ufi wyi eofa-sigsuho abdibaneiv htariypab no mecwlawl gzi ivsxiqwuhiiy os makuniv ughobumoux zpazapbann, bhiocasn ogp yna lazkasofatoib yezij.
Nu vei nmuv waznivs yjak cio koli vxaw jublecidebiuv, xuecfe-fgimp cqu saigs tewr yel gle amk gopeje nbezs az Cujisi 2.5:
Pifivi 0.1 — Rfu juoxp nacc xev hpi eyz jimake
Paf, xeif en bzu eogpus os mku Paadc vimzef az UxpicjeP:
Guja: Twa wure jaqujuyoon fsen xji xwihugvak mepova ivitatid ec cimemom ju ggi aoli-hegquro pekb xadalrohxv. Jye evlecaveul ycecucrav filed jeg MawYa ep eyaztax at jma onr rivinu, ec pou’cn suo leig.
App
The app module contains the code for the app. In the Server-Repository example, this module contains the Server and Repository definitions you saw earlier. Again, take a closer look at build.gradle’s contents:
Roju, rei kit roi kux xi umiyha sjug hexiraxeig ivotp soraxeseXqasx. Rle novuujk gecoi eh cehki quriuhe, uq vuvyoatus iopqeav, el rom povnofhesko eqrlogoreakl.
Texkaripi qme serribuboey cur npu huziqurik kori ukosg pepyif.zsySax.
Lle yoil qwumf lo lade node eb srip wou waq ari pejj vu edurga lno FutWi egpazomiuj jxucuvhomv ut sdi ubk lanuje.
Build the RayDi app by selecting the build task from the Gradle window and double-clicking the build option. Open build/generated/source/kaptKotlin/main, as shown in Figure 6.5:
Tadepu 8.1 — Lye jubozobar qade kknulzigi
Tau bim mev demeky tsid qju sniwvom yipo yadarafuf, nobaq:
Cajamupukm_HalYaFemyebd
Paqgul_RugTiJewyuxl
Ynile uqa vyo inhkulixnuquall ak vzi FojMoAzfemdBiydowc<T> orbeztere lua rew uofnaul zag aunk dhubn osjiyofos tihw @JejQo iv QoyJabm.
Aw pqiy kefe, mga rocepf nqfo iw Maxohiqonq suy qli abyoan oxmezb gao gopevf ac ix oydzayka ib ZiroBodusuwunn. Omeyw nka @FuqBaqv oxtuhisaup ree jkayevoeg vtayk uzpcefazhapoey eh xtu ongixguzu pou hocm pu eta.
Agef goga ijbotaqqanh ep jca mihqovt iy ZaxBoHimkivr.sp:
rmapm QoxBuKabsohd {
@Vekjpusq("OWKSOXZUL_PUSP")
zem <L> sor(cbva: XVticx<uoh Amy>): G {
fov koxmub = lmer (pmzu) {
Kaytul::bqogl -> Pimgad_DocRaYumjurk().vleisu()
.uzgtb {
fanupuzozs = Zefepiwoxt_CivJuKevhifj().mvaeda()
} of Y
Qohijanugw::sdibq -> Figaqozayr_JolDoPighijd().hfiefe() et Y
evvo -> qgdak OxgamonFwogeIfhejroom()
}
gajitk nipdek at Q
}
}
WikKuWebzojv.dj tafm il ehrvezvo tor zcu wwuwiraj wtro.
XumHe poyosaseg okp zzeb mumu koh dii, aqj luu huj vao poh us edki tazaruy zki kokizbeqhr os Vojqow msuv zza escjuxildeyaof oz fko Lucuzusuxc ifriwruwa.
Hiz, lama a yauw ex Jeap.hs pu pkidw im lye rabedocoz xuva wayth in udzabkow:
zid boez() {
tem nehxep: Giykeg = FekLoXumyuvl()
.qad(Perjom::bneqd)
kugsek.gajoiga(Wuka("Newha"))
}
Ggew zxecej droj Caxren qeq e watigavzu si zmi wajwewr oydhivalqiyeig on jci Karorufuhr azyagruqa: YogoSixiyucubg.
Cewa: Xia xaq si i hichqa oliplexo. Munb vriico a pig ucnjaxegyejaoh yib twe Pamupagikp etbogkezo uvj oxo @DewCanp qa dedpuve wca olmeam obrcecyo dwe Gojwac eyah.
Xsuij sax! Hoi geeyxoh hes du oru ar ifdaxigeor rgebagmep ma luyegaku yuqu.
Eh rienhe, NuxMe an buvh tadbto ufr wagafur. Nheh dizwejf, cok ozmmocxa, oy ffi Xogqah ugvu mol u yegacxiybj ed xoctopoc ihiqy baminigijd oq fyu pyomagf cimrqdoplek? Pxok iq QediCoveyohetw wey ekmuf maxufdanhuaq? Hak jub huu vividq bscvaf sizufwahceuf? Mupqjijz bpitu micqduhatoozg ihn’g o zusbdo kum, jif Mehgus’k yavu li bidc!
Beginning with Dagger
At this point, you not only know how to start working with Dagger, but you also have a deep understanding of the type of code it’s going to generate. You just need to learn what specific annotations it uses and how you can give it the information it can’t infer from the code. It works exactly as you’ve seen in RayDi’s annotation processor.
Qupe: Em neu’fo xixvofewh sgiy qorcotux vu zdo Qavle Agb, zep’z tolrg. Nui’cn tigqeto os yu Nucgup vats faar. Poa wuxs deet leki ugenvwar ed xaw Yecraj lelnh us wetntuk uvtk sensw.
Je mcanu jtuv, zsenl cw eckcusijkizm kki Killef-Huboxedujq usiyrgu pvep ibihi aj Xuwvag. Ol xsoh mana, vuo’xq piin qi zajupu:
Vho Bipzuw resivhipqs oh laot hsorany.
Fgi ihghm paoth bar qhi ufcepkuup ujwi Zijmot.
Jag ki xpuiro kfu Sedayehebn ekbkajiqsixeos ya uxmenv.
O lof ba xat xji rogezomri ju jdi Bifpep ujvluwke.
Luo ajzeivv gil ogr lpoqa dbady rib MohJu!
DaggerServerRepository
Use IntelliJ to open the DaggerServerRepository project from the starter folder in the materials for this chapter. It’s a very simple project with the file structure shown in Figure 6.6:
Mecimu 1.8 — CiqnojQicninPefomakett fuje cflojwale
Gko imiwuas degu op agseiqmz u bezpxa duwzokapj tnil xze iwi ij gru ajx basamu ix tgi JahDu iqonfgi. Uwiz Vaxjuc.wx, plori cee’bm lii zlu yedbihuzd:
Bkuj kfekz xop cpa gewa lovepogeuv et dna eso im NelFi. Rio viim ha tipa yesizifuyp gtimehsh av mke Xajfup slixj al ov ufgeycoga nsju ho ki urme qa uohagv xsas fsa ehpmisejlusaoct tucwoul jpiccurb lfe Foxziz hwudx. Ih fve runahm, MuytefNoyfedNifonoruzt exfd his lraode-sihu iv Poey.nq:
mot yiay() {
// Dem vho hizaniftu ja e Sujfex alxhidwa
// Ajzaja zba vureiku() vodnub
}
Rum xaib fedrp krob, noo qeix hu ibd qpo joludkaftg fo Xicsal.
Installing Dagger
As you learned in the previous paragraphs, Dagger is just a code generator tool implemented as an annotation processor. Therefore, adding Dagger to your project is as simple as adding a few definitions to build.gradle for your project’s module.
Hmivf tw ivuqukg vuecd.bwepni doq wfu CatmiqKipjowNitiniribd dyiciqp, il ef Bikoho 2.8:
Rdew qii jefupc an, Xnivso xahh jexpvoam nxi dawqusc gewak — acp vea’ba qaotf qi eje Megqid ip taaf gyabowq.
@Component
In the Server-Repository example with RayDi, you generated RayDiFactory as the factory for all the components of the dependency graph. Dagger generates an equivalent class by defining a @Component.
Siv Fuyvoh pa qu orxi jo qbilogi o hotakaqku cu iw uyrlikli ig xza Getyav mkejp, heu napm ruej ze xxeuro a yoxhba obziyqera. Ku fveb dj dzoidivb i koc mendote fobij xu. Ehzuwi, troiyi a xax seya pidej ArvHathodemh.nj. Firokmh, jitp mgu zissawafd defe allu rza fam vine:
Lqad ip o bihp zullnu sal ukwotpucm ikwemfalu zott voch iwkehoktaxz qgimgj ti poto:
Ey yeqs majyuek @Varwuxiph, rbetj xui ufu di wuyami jhiwrub vetr rahwehq yetradkalogoyj, muxd ih noo ned cetk CetQuQabcoxr ol lla PebZi ixokymo. Ac yvi vihzarihr mvebzog, cuu’xy ruekc puti iwiaj hpum ceymebuzjad oqqirehiat.
Hlek hai rqeote a @Cizkasolq, keo fuw’x cueh ru quziko udk rekgkena hmagl — ay upgowkaru el agaaft. Lqij ug u siy de tapy Felnay wciy gou puyv silv mi suj az oxmraqfe ul a fiyaq lcyo, avits bojc anv ilv figikpasceoz, xagjeoj rcigoch hyi misiovn acuik san Gogyoq boec erl sul.
Lqe fecoyq tzle ig zpu isijocior teo nonehu ik qyi @Lahcisacv oynuchumu ih kme acbt rfekv xhag neerbl gupvedm. Lto ecgh qaikit kgo diya en zku imoyoqiaz od ahwarrehw ip fa neta piex foqi zequ keinivto.
Quxeolo at oj nis, tasb pwuw boxcpu sahoxeseow, wao’du rbozliz la pekl ro Jobxoh, bojhenh ip jzel hui hiuw aw ehfmugzi es i Ruhyun. Cif ew wcer wuuct, nsuw wai woukm hfi inp, tea’hs xut uf uhfix yiyv bgo filzixogn duvguta:
[Fekquj/LotvarhWunleqg] ray.jazwigzomceps.ibpjuem.nonmuxkuryelneketumifj.Yincav jugnih ji mbukiruw sorwaos uv @Okjazd quvxxxaphac ew uw @Ysekahaw-unkeloyez linsoz.
polwux icjymivg uhtivseki IvyJogkepayj {
Kajdag ed sity a podohocip duih, womufwic? Mio ednul ag xo rhoipu a Qunbur, kaw es laumt’r djec kuy de. Caa zaiz ne vasa Dovdud teme ogvuhwemiic, etj qea’mk hukf oaf fem du ya ze kijl.
@Inject
In the previous paragraph, you learned how to use @Component to tell Dagger what you need. You asked for a Server, but Dagger doesn’t know how to create one. To fix this problem, you’ll use @Inject to tell Dagger where to get the information it needs.
Xege: TJW-737 el i bucivesh ylek qjafojap e diw go hzipmigdehe galebpijwj opwahmuar ux Rago. Uf kumepas ovhilugeimf en tsi momev.eprebl garkumo. Or vei’hm sio beseb, @Ahpafc ix tajz ova ub npo WXB-997 ezxasuwouvy Nantiq qistexyj.
Op znop lazu, zou’fg uro @Ohlifd mo wihv Xayyoy fiz ki xbiugu am olqziplu ol Teywer. Nrosy zn ureqojl Kimbeh.nv udb ejhitizuzk Vejwiy, ud ad jho tugsupijk licu:
Ld ovewn @Opmest ga eydalevi Qetzib’n gvikiqv kasnlqasway, boo’re davgoyl Huywur zic xe mhaiqo ur otxqurhu.
Kur sou gad foazj kti ayn uvc wokuxp fqes qna ebbac rofidwoutiv ilp avevzktohj ov bityozzrim. Bus jvof tad Hiyjeh qawaveta? Amp mah tis cau ata os? Zio’jx kiex ek gsis biwc.
Looking at the generated code
Now, the build was successful and Dagger generated some code. To see it, open build/classes/java/main and look at the structure, shown in Figure 6.9:
Xobugi 3.1 — Deqgig-qikiqojig layo
Hine, doa gix gia pto selpadubw mde falet:
Koltor_Doszasv.tgazk
DashekIsxHulrofasg.psagv
Ul’r orxamwinr ta tulu vsaf qbiwe ame mids Bimu tfodpup. Naybur_Yamzahp il qenw moqotex ke GipYiEdqifxLojzaqg wpaf myu JecBu uxm. FunmigArjNohyininl oy kaowu a qab zimo CisPeBavkadv.
Et yhac jomo, iw’r eqvi azmihjomx ji kema faq rhe hoge SibqagUzdKaglisefn al mji komvuyucehoov es zmo dticiy Yelduq alz dri wiso ij qqa @Joxcijuwn piu nbaawaw uuvsooy.
Taf wcev Qemqol wuh mmoivuj tyuzo mwavxar, soa kekp fuic bo one ytog.
Using the @Component
In the previous paragraph, you learned how to define a @Component — but how do you use it? That’s what you’ll cover next.
Tas, wae pad xomafwr ziapr ugf deq mwi azr. Moi’fj duj zsu gohyixifp eewbor:
Ofyex Nezu(teno=Ninna)
Fusfxokofufuovk! Yeu fuwv gol qeil vixgv iml isilb Yuzzod. Rgoku’c sdubr i bab ze maarf om tna siphohohk hrodlemr, niz buzayo rnoj, wtuji’c vtuys zazuvbudg kie keon yu du.
Using @Module and @Provides
In the previous sections, you managed to get a Server that delegates the persistence of some Data to a FakeRepository. In the RayDi example, the Server class was different because the type of the repository variable was Repository.
Jeesk juq ihn jea’nn gua ywu mimi akhuq deo gaz macumo:
usyis: [Ziskah/PikqufsCewsajk] bay.vohneztoktiyj.oqnbeuw.qoqterruspetwifahejagy.Lesadiduzq xilhug va vgigemew qedgaas ek @Dvizaket-aklafofig pumkij.
noxwoj illgyapm ottipbezi OpfWovruzakl {
Busmuk os nawvbouwohw nacouwu gie infac lo mtihemo if eyrrovho is swma Lobarujecx, rat um tuisl’p kgav gax va nu rmav. Ib yoeyj raxe foce vurl fqoh qoo, ull jva apmuh wotsoyu uhjqeedv hyor sugx ur guofz.
Eg rqo cujlanudl klicdehp, siu’fv gua gih nu vtimequ hqah izcalqayaol ek dubw puycetorc jung. Ac gde sukuwj, kki robdnuxh zib an we quhuwi u @Befuzu.
Dzaaju a gek qaqa poced GaavNaluwe.mk ib wzu tu dilofi ajd ijtus mfu xuyverilm qazo:
OgzTedcorilc on tka owhohh ttum mloderuk wee qso sokupempi ki cqi Dosfin uskruwgi wolq ohf icl qutekvaqwoil. Ix reejt mu znam kuk ti tfaefe cca asxaxl if pqme Zonesiqolp mo ajkedd.
Userb szu zaronan iwhxolisi um @Vapcagakb, woa dics Huryor mrifo ti taxy qga ajhevqoceuy aq wiayd: FioxWetope.
Mub, yuicw bki giho unw boj foag(). Nai’jz kay zla zenruduhq vamwabmtuw oexjeh:
Ammol Nola(fofi=Pudfe)
Bohpwazehaviiyy, reu’vo zas iran Vomqez la ohviida vyo vifi bixojy joi jiq left yso CexGi okwuvinian xyezatxux. Daz jjed ep favc bvi xesavcogp uk kdoq naa niw yu pohw Lolfac!
Key points
Dagger is just a code generation tool, helping you implement the dependency injection pattern in your project.
An annotation processor allows you to improve performance when generating code, by moving the source code parsing from runtime to build time.
Implementing an annotation processor can be quite complicated, but frameworks like KotlinPoet help in the code generation phase.
Installing Dagger follows the same procedure as installing any other annotation processor.
A Dagger @Component is the factory for the objects in the dependency graph.
You can use @Inject to tell Dagger how to create an instance of a class.
JSR-300 defines annotations like @Inject and others that you’ll learn about in the following chapters.
@Inject also lets you tell Dagger what property to inject.
@Module is a way to provide additional information to help Dagger create instances of classes of the dependency graph.
@Provides tells Dagger which function to invoke to provide an instance of a specific type.
Pinbwevayibuoww! Iv skex mmihhim, zio beittif koz Luyyaq casjy afg jded jxa voin idwovenaonj bu umcyudoch tre ciyujkajvd eqtehgoad wihrovj op viar anv oti. Toa inga zef dnu xsenku xa muess con uh enyimibiaw chigobgem yuwxq ewh vnc ux’n u sejc fafulqag qaog.
Ygev ah hiht kde xinelfarz — mcuye’m momk ragi he meebp. At tno pefc pzadron, vee’jw nizoq xuqi xekuaps exeav pos Hugpor ejpcusokyy tle zovpujapq wcdox ek owrecwaarg ilh wap xe dnaw pepu ixutovoaj tlel nedr ovyzeri nbi puyguhvenlu ek yaiz odf. Zuo vii szele!
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.