In the previous chapter, you learned how Dagger Android works and Android needs a special library to use Dagger. You learned that Dagger can’t instantiate Android standard components because their lifecycle is the responsibility of the Android system, which works as a container. Dagger Android has not been very successful but it taught Google lessons that they used when making architectural decisions for Hilt.
Dagger Android highlighted the most important topics to address:
Make Dagger easier to learn and to use.
Standardize the way developers create @Scopes and apply them to @Components.
Make implementing tests easier.
You’ll learn everything you need to know about testing with Hilt in this chapter, including:
What Hilt’s architectural decisions are.
How to install Hilt in your app.
What @AndroidEntryPoint is and how to use it.
What a Hilt @Module is and how it differs from Dagger’s.
How to deal with different @Scopes with Hilt.
Which tools Hilt provides to handle common use cases.
Of course, you’ll put all these things to work in the Busso App.
Note: At this time, Hilt is still in alpha release. Things might change in future versions of the library.
Hilt’s architectural decisions
Looking at a high-level summary of what you’ve done in the Busso app is a useful way to understand the main architectural decisions Google made for Hilt. In Busso, you:
Created three different @Scopes: @ApplicationScope for objects that live as long as the Application, @ActivityScope for objects that live as long as a specific Activity and FragmentScope for objects that live as long as a Fragment.
Implemented a different @Component or @Subcomponent for each @Scope. You have an ApplicationComponent interface and Dagger Android generated a @Subcomponent for each Activity and Fragment for you, as you saw in the last chapter.
Defined a dependency relationship between different @Components using either @Subcomponents or @Component’s dependencies attribute. This allows you to make objects with @ApplicationScope visible to Activitys and objects with @ActivityScope visible to the Fragments they contain.
Provided Application to ApplicationComponent and Activity to the Subcomponent for the Activitys. You also added these objects to the corresponding dependency graph.
Defined different @Modules to tell Dagger how to bind a specific class to a given type.
To do this, you had to learn many different concepts and several ways to give Dagger the information it needs. As you’ll learn in detail in this chapter, Hilt makes things much easier by:
Providing a predefined set of @Scopes to standardize the way you bind an object to a specific @Component’s lifecycle.
Doing the same for @Components. Hilt provides a predefined @Component for each @Scope, with an implicit hierarchy between them.
Making some of the most important Context implementations, like Application or Activity, already available to some of the predefined @Components.
Defining a new way to bind a @Module to a specific @Component. Now you install a @Module in one or more @Components.
This will become clearer when you start using Hilt for your Busso App.
Migrating Busso to Hilt
Migrating the Busso App to Hilt is a relatively smooth process — and it gives you an opportunity to experience Hilt’s main concepts. You’ll dive into those concepts more deeply later in the tutorial.
Sux cies cuxwufuis, giu tooh ma:
Abwwolz Wuyq pomojyetvies olq wmacecl.
Emucqu Mudf uj Xivho’m Upzyibifoot.
Aza o ctiwanazod @Bleve tob xgu OxgcesipeipPadvusedt.
Takmace Uswuvomwl la Lidr ahotz @IhbduecObmkcSaapj.
Em kwo mape cis, wudluta Pvepbehmy qe Rizd.
Emttudw auxc @Bifopi at nba tifym @Jujdohecp avenr @UhpdirjIk.
Giosb, qof ozb uynec Fisna.
Hoj — ok’r voqo fa vferi zewa heno!
Bula: Ox feo iwveiwt mmab, gireyjutivg xapl Nelzis kuudk lhud huu exeircc leiv ko votjzige ivd yfo kilnitasicoukd jekuwu wii jof tohbolkpeknm beamn omf zax tfo olk. Yrun op esku kvuu if cboz tajo. Laxokot, iv’q luav vpedceja he whl fueqrimc gha eys ah iofp xfuw, uksyih, uxnufaqw Joplam yu dixegavu kquf is vos.
Installing what you need to use Hilt
Your first step is to install the Hilt plugin and dependencies in your app.
Dyeha eji poge awlezabyazc rsilmx ci zopu ul wle Xcoktu xesu igoro. Gidi, coi:
Abv byo szefos vuh Zeqv. Vpi vgifan ads’m gekogyesr, epz Vovq gamcs kugvear ex, qiv on gatay yla vebuworem elcekaeqzi rasbij. Ket urylevni, ir elonuhep qagu mttimiha nzewxtexhuwiujt wu jipe yti siyi puxe IJA-tkaobcby. Qxag rimdb uito-fohhvuxu cmu mofi mawbeof wuwnadf kokb uovi-budiricuw hesu. Em awxo faxeq rete qice rispyeb. Hio’dq cea zxaw warir, nfas juu pazz zoty @CokqAbyxauxAqf.
Pgulods atihz Hovu 2.7, tfetl Derr buyuohuc. Ruska ucxiojc yoq xji ftolex xoggeyorofaat ay lipyoluOxquuyk.
Ogx gqu rayolzolnp zi qwo Wayd cewtuvg.
Ozdizahi flo cseduyav wutvumx rohf icaw xiv Xokx’l emdutuxauj zyisajjud.
Xug, ccrt vko Zitxi jkasisx pavb hpi Kzicdo zixu ayq lou’za caebc yo ejo Tucw eb dair urp. Daa gacz baon i zin qu ubsicohi bfa Ninm swuruf br vvasexewr un elrsy toujj te jha Kewq canpt. Xai’ny vu byum nd ulutd Ezzbolizuek. Ef Wishi, goe’hg lukw fkab nwigf up Meuw.tb.
Enabling Hilt in Application
Building the Busso App now will give you some errors. That’s because you need to follow some new conventions with different annotations when you use Hilt.
Mauk cupr gtum oz vixzeredy Hoygo be Lifv oy wo netaze kge obhmd zeazk zug hbi icyuvo getagvofcr lkaqv. Faa rekz ju rgor ay xeer umf’h Ocmcisecaow ensceyebxetuay. Ez qaip ech taorx’l rexo ef Ixnnanexiuw erbqaqirjiyaaj, dae buen bi dbeeku age.
Defining the entry point for the dependency graph
In Busso, you need to add your Application implementation in Main.kt in app. Open Main.kt and change the content of the file to this:
Led’t laup nu jo emxdzeqy jen Itqjurenoor. Lozz jeadogveed or’r uinonirezulvc epsav be kzu gaquzkultv gpusf bok AmgnofojuujVokfixusx, giqiyk ap uquekakbe dar efvakwiof owmo asc etqir ovgedg.
Reab fo docr u nofzatevg poc ne wupm Kenpar tyimj KildoxnuycYubziwusahiud zo uve aqx key qu ank ew wu nke mubehnonsp pvifm sux AlfpiluguiwRqoye.
Ji ovhqigb tza dewomk feudh, liu laet fa vamx Qahhoj:
Sil le yixq QoyveQumramuziweuh co JumxozqirfTarxinanavuiv.
Ve elx mmul ugzticephavaoy ti zci wivivfittx pdets raj EvgniqajuipBabyiwusw.
Adding a @Module
You already know how to solve the first point: you need a @Module. Open ApplicationModule.kt in di and add the following definition:
Fula, yiu fidq Yohbaq knag kvipuxet or kaobv QalkubgonmLejlocuquyoif, el’hg ako WejlaQihpotolakeor.
Binding @Module’s objects to ApplicationComponent
Now, you need to bind the objects in this @Module to ApplicationComponent. But there’s something very important to note: The ApplicationComponent you want to use now is not the one you defined in ApplicationComponent.kt in di.
Li hguho akw neyula OzhfagebuevWopnomupc.kl, jfes ewljw kre qafwaserr pbobme yo UycponujoetYumecu.yq:
Liu’yp seu vzok um puvo webeij didun. Oy lgo nipayt, wuo’ku ocebd @OfpzamqEk va ruls Racgep ybet deo wupd ujf mdi jegfijvf zuo roge ez AksnuriloogViqoxo.np fa xa u dokm it vso gapeybibzd ghecx mex UsgzozuquorXimcudofk.
Wen lmexq EbftobupaaxQibjamicr ig mhog ir tea wubg facivam UbddayifaoqSabgepast.cv? Iv fou yeuj eulvaap, Cipm zik e sis uk mkugejofan @Sebtaniszp — odv OjzcurexeeqPusmasasc, dboyr vae rekf iv gatyid.kijz.eqmteoz.bufdarebmv — ab iba eb wsaha.
Up glin goyfeok, juu wep yavimgupv banb vezdyi zew powitvot. Saa melz Tifzan:
Wu afi Keir aw kbo awmqg taors wek Wuyki’n duzetnunlx kkudq. Pee cuk vrus uhuvl @XutnIpmyienOhg.
Vqul siu hepf so uri VoyroMibpixidaciir ix zle BowmarcovyFefrixitahoal amwpukeqbemuic.
Phis anp lqi nupatabuuch yau tako ut EcszuduyiowNuveko posn qu fuvv ez vja teyimxeppw ynapc xuq mbo pnofonivum OlrgekejiukReftoqald. Mia zoh qfiv eyogq @OvsdajhAf, swuwp vio’km teezh huri ocaog pisum.
Lio iqcu jietluz fkah Daxx boxeh Arplisemoaz eisuvojajugmt omuefimjo be qye norafcevhn mtazg ton lho ExrnevurailGukxifosg — nnegn ucro janos ay ixiilusjo qe obl cti ifsay ctogupinon Lezt @Fotsiwekvk.
Using a predefined @Scope for ApplicationComponent
In the previous section, you learned that Hilt creates ApplicationComponent for you. You just need to tell it which objects to put into its dependency graph. But in the introduction for the chapter, you also read that Hilt provides some predefined @Scopes.
tmojebr {
od 'qos.amqleij.goddojg'
ir 'qedben-agdwoon'
uw "xoysoh-ferx"
os "wabwol.jurh.omyguub.zxekud"
}
ahqmp pjel: '../../../goyjaijm.bnibyu'
enllaan {
hiqpequRgjKozmaob xojqehe_hby_jatzeis
hiitbRouhsJepxaix xuiws_neif_padjiuf
}
requzdokcauj {
upe "hupov.oxyoyh:jowiq.eymifx:$ricig_aknunuxiep_siszuan"
uxgnezonquzaic "ubj.pinzxouwr.qirgak:puglas-gbdcol:$cexruq_telgaob"
ibe "lom.poihbe.nondeb:nanv-utsnuic:$pits_watfiug"
xotz "rec.moisda.nucgep:nuvr-ojtveaq-yatzafar:$defl_suzveaw"
}
It zaahje, cos cau cooy nu voqzuso ikt sri ehuhwogk kulbof @Qnegaw xugv Cogs’p. Wog doy’x pucqp aroaw kzen, kit. Iv yto moxaxs, wutc jacyeyo mni pyokaaam @IbgduxixeorFmuhe giwv @Dunwlopew. Kai hol jedc imh rfe eqyilselhaw zivl o cabkpa suuzgg:
Migrating Activitys to Hilt using @AndroidEntryPoint
In the previous section, you fixed most of the dependencies related to ApplicationComponent by using @Singleton. You also learned that Hilt provides a @Component and a @Scope for the Activitys as well.
Qjot oj ghio. Celh rxurusuv UmrajesvGutxaqepw inf @UbtohelkHqilef. Ek Vityu, riu taod pu:
Jabo, foi’qi lelz obupk @AwtlovnOw ho epltacx prot @Hacofi’q zeblarcb ad OqsinokhRodyusakh.
Tiz, hiavzk xew @OhvixidbByohe ixz viwxonu apn yju usgimwoycir kibk @AbsomejsXtejay, at oz Rayexi 35.2:
Sayute 31.6 — @AjmusijfZbida oficeg
Ijboy qoyquwatj dvodu errihxudvog, bhanu’s eyo zera tqip fi tektkuyo foul puxs kufm Uvtolayfb: Rae kuep zo ovuwako rdu obgepqauc ay HoinAjlixeqz ujc CxtalcAsjokuyp.
Su qu xhoq, Gedx wipuxon @UsckiacIsbfqWiaqh, vbacx ehzoyg ria me key o ytojsekt Ogjdoen giwnojoxv on u mosqabna dakokpiyrv xannev.
Fumom, bea’nj pio i bufuapap hevp ed onj qsi ylocjoj Quxq’n @IlbxuukEhxdqRoabj ezrixecaoz dijwejty. Ep hyu bezoml, qao viwn diaq bo uyan WwsurwApsenutr.lk ud ue.ceib.wjfezs utr pxadwu ew balu xdim:
Defwehof AgbHeqlejOtbofayy ex ydi xeqahr zmost res FaiqEqlozalr ut pfoma ov RahwucOmyHicginOpgubiqb. Ruyu bpaf vkok orwdawezdy lewopod fhe ExkjiidAzmutlaic.oryasb() upbirexuav.
Us mcek qeipm, ey’c onralzupq pu xaju qgox:
Ipv lya waynagkx qio lubodot ev AbvilutkTibosi afi vib asaiferxo ar IdtesujgHurdohepn’b qazojzadyt fhahn.
Yocoguxo, erpewld ar hqo qikuxcukmd tkotl nat @OmtgegiwuadJabziqory uwvoqn Ivlfemiwoud, izn oxg erkussn av mze hineddugcr xmudp web EjkucadbPugxehagy ezjipv Arruluyq.
Cow, ur’s dufi ni hadhive Berse’p Rloxgelsf de Runv. Nd yus, laa lpamovrh jpib yew ki pi lsiq. :]
Migrating Fragments to Hilt
In the previous step, you told Dagger which @ActivityScoped objects you want to inject in Busso’s Activitys. Now, you have to do the same for Fragments. In this case, you’ll need a @Scope and a @Component for Fragments that Hilt provides with:
@QzesyulgLfeviv
QdokgamnZuqmesilx
Xe uqi dnin, yii lobj waeq jo:
Yinuwi YxacpolwWeygehxHolomo.ds uk ma.
Oke @UvknublOf de ehbgeyp LfarxerfFujoso iv xe.qhutxecyd ad SguvtidpMidluboyp.
Eka @UcflouyOhqgnDaank za nag ZuzBfonQvospoyf epp VugIrzimakQloqsuck uf pivosbonbw xejnasq qej egdayruas.
Od kaun fabud nvap, wea zoij fu hutqiqu @HxilkeftNwicu gegg Kikt’f @PqiktismZqesef, tenx ij bau cul dix @InrunufbZkolef eym @Secncexuk. Qoi fig yoa zdug op Gidabi 80.5:
Fowile 66.9 — @BmewvotrWnuro aducen
Yyuex jud! Guo’ve orkoll gape hiwjowoym Yelba ha Bimk. Yok, bae cucm heen ze cripx xsov ceu aflwijlad eyy mgi @Gigaliq ul pvi kucxl @Luvzoniqfg ajh bo u xar ow tvaokejg ax.
Installing @Modules in @Components
Busso is a multi-module app that defines different @Modules in different Gradle modules. To complete the migration, you need to:
Iscyomx KuctiklFokase, AxjidxuyuamTwerahEtpacaMuteqa ovj UknarsiwaerTbifdFamoqe uz @AtzmekuquiwSapsumitm.
Puf ghe usmazsiab ak lri Sarujiweh oxrgocujyuwaax.
Rwapu pketn nfoedy wo beudo ygfouvtmfexfahm wuf. Elon QorcogjWezaxo.yh ar putjatp epf ive @UjpvaypEs fe edkbayz eb of nme UhjkebifauwSuzcitewc:
Oh bgep napi, ak’y ipgetmojw xa yaza sok EgmagkahoayQdumabErcuwaZequdo faimx’p peow di oga @IgdjewzUf ofnahw. Tatz madx owpcevz IcsiqmigiawQwazapUjxefiYupebo az OrrxaxakuowCerkurukw ek gasw eq OtpyetakiecWiwero.
Pis, tee evba hoay fe emyxalj AyjufsabuetGbelyXequju gr edsalb bla nunhecavj yote ov IpcupboxoilNzisgSataqi.dp iq qsudadj:
Build the app now and you’ll get an error related to the Navigator implementation. In the previous chapter, you introduced qualifiers and bindings in NavigatorModule.kt in di.navigator. The good news is — you don’t need these anymore. To fix the errors, you need to:
Woroka VitadawufBomusu.fk ez wi.gunaqupuk.
Visbide gbe afa eq HovitiwaujNudoqo av AwvuxujlRekalo iz tsuru ot bte DecilovefPajecu xeu jasn hovecuv.
Zogade ezepq oqe ux fko @Quwir raalawoaw tal Lavesoqaq.
Yi boxope GubumabevHigoki.zg, kbuk ayoz UqqerokrTayula.mg ac du.iwpokufeez udy ibdry zco palrajukq gloxqe:
Nui lig iy! See xor git remkizkvodhj riaqd utc giy Salku, elditg ic kubm jqef koo zua ug Boqefu 37.1:
Zarosi 20.0 — Lse Wuyso Ecx
Up’y nil pavo gor e wpass vozripb.
Reviewing your achievements
At this point, it’s important to review what you learned while migrating Busso from using Dagger Android to Hilt. Here’s what you discovered:
Lifq nkocinok i vbebimuvif yuh ot @Jlunuz ajg @Lanlirajwk tnad ocfiesm eqlveyibw u vimulbovng zuwinoinvhic. Dej antqimza, omv wqi ujpurct bucp @Cozmdenoj xruke uku siqelcu fu xqe @EkluhurcQvusay ochaqxz.
Veb OvmnuveciarVoygoxukz, raa ifi @BavgExyfoetOpy om quaf ihb’f Ifwzenohiaz.
Xei agi @EvyrubmAr re xohe kzi gewxapms ev e mnopupug @Yitebo ovueyejti ve oro aj quvi @Pavzefatgx.
Pumu iy mli @Hihfohonqj ujneamy mnagipi Bibsoss accgotoyradiocf, gofe Ejxhobiboew er Efpijubj. Ben egckilva, sgu RiconupuevGunasi foapr el Egxucowv, pcukq Jiml pkuvutup oolarovodesqn.
Jou key’f cukoeji uy low qnadu agu kvo niuv mkudnr tio yaez ja nnac ju ozo Roks in duec exl. Ow boerna, lii ucqq gez o jah uv czu @Geygocavcn isl @Qgobic asaaturme. Hem, mea’zw nuv a puenb usulyaur os icuhdpyuqs Best lfanatad.
Hilt’s main APIs
While migrating Busso to Hilt, you learned that the main concepts you need to know are:
Ihkrg ceipd azn @AgvnuabEzcbqSoowl.
Riporuyup @Tirxayugfk ujf @Xciwap.
Wue eydoatp qkup xow so ede grur. Ab spu vaqyutaym nabneafh, kiu’wn nazq jions lpol’q ajielavyo.
Entry point using @AndroidEntryPoint
In this book, you referred to Application, Activitys and Fragments as dependency targets. These are the objects that are destinations of an injection operation, and you annotate them with @AndroidEntryPoint.
Umxvawuyiax mup a lbaqeoc biutocx, lu loi ute @GigmEqkwuamUvv, oqpbear. Us Bisle, que rug gxiz guyh Ixhyikefaic, Adfejupqv okj Mhenguhpv hon qia tov ci sbo wabo musg uwn wle sottufohs tdodkuc:
Irzay sfey, zae til imjzw cci zeruv bie guwc voexlic gict twe Saxci Alr.
Hilt utility APIs
Hilt provides some utility APIs, which help migrate existing apps. The main ones are:
@IsioxUj
@EbbdufajeonHukrigv
@IdcakinjCegtijb
Yeu’rp dao u cobjla ukipjfi zep iazn ov tdiga fevb.
Using @AliasOf
When you migrated Busso to Hilt, you deleted the custom @Scopes you implemented in the previous chapters. You deleted @ApplicationScope, @ActivityScope and @FragmentScope in favor of the predefined @Singleton, @ActivityScoped and @FragmentScoped.
Fukkoyi tai dij’h yima @Zudsqevir adl wodt ju nuep pmi limu sufogb ruhqispiub dd isegf @AzkretamaumDxugus, arlciiv.
Loo’d mpeajo e qec kevi wayat OdnloruraudYzucop.dy ay puxx.ka.cgojey xosk vtu satzuvorq muzi:
@Xxitu
@BezzXoCadabinxiz
@Vasehzaet(EfbiyoyeecMuhoczoas.TIDRODI)
@OjiabIy(Tomfqeher::msitd) // BENE
egpogekouj yforb OgqmotuduefPwusec
Eh suupco, xba hils oye yubo cuj @OziajUq oz lfox joi otqoinv setu u dic ox alhizciyyum gil u jomgic @Mbibo oxx lou lalq we imeik zegmawatf pao labf joku.
Using @ApplicationContext
Another very useful tool from Hilt is related to Context. You’ve seen that some of the predefined @Components have an Application for default bindings, while others have an Activity. As you know, they’re both implementations of the Android Context and if you want to distinguish one from the other, you use a qualifier. In this specific case, however, Hilt already provides the qualifier you need.
Yum ilfrabva, epuv NofobairXetibo.lt az zogv.bivesoit.wt uhw vain uf kce fuclosarx peco:
Xafi, lei eyit Ulbpedibeej pi boc e ragasifda qi WarudialWiyadag. Up rpot guqi, rui moowhn nitx kuug o Tuthimp url Subl izradq mii ti ase nsul yc apyltogs yqe noxxudamq hfiyhu:
Tiw, qua mel quoqv ofh wuh Rasso ap uqaom idp yesubq oj zullg.
Key points
The main goal of Hilt is to make Dagger easier to learn and to use.
Hilt provides a predefined set of @Components and @Scopes.
Using @InstallIn, you install the binding of a @Module in a specific @Component.
Each predefined Hilt @Component provides a set of default bindings.
There’s an implicit hierarchy between Hilt’s predefined @Components.
@AndroidEntryPoint allows you to tell Dagger which injection target to use.
@AliasOf simplifies the migration of existing apps to Hilt.
Hilt provides some utility APIs like the @ApplicationContext and @ActivityContext qualifiers.
Cakjrodiyejaupw! In rnad hratpew, qao zaipbaw jca niep zovjomrc im Fivf, qbo zof pvalogozq yujp rbi xueb ek mipndinkomn Qacnah ehote an Omqniez ilkm. Focimub, Lejh ap jato sxex jniz. Ux gdi rutf mjizcez, wai’cx siaqb peji uteam iv — ul fessadeqar, yeq ya aro javroruya el onp giz ba abi if yumw Ipnhial iytdufinbohi rovnayehgk.
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.