In the previous sections, you learned how Dagger works by migrating the Busso app from a homemade injection framework based on the ServiceLocator pattern to a fully scoped Dagger app. Great job!
Now, it’s time to use what you’ve learned to add a new feature to the Busso App, which will display messages from different endpoints at the top of the BusStop screen. For instance, you can display information about the weather and any traffic problems at your destination.
You also want to let the user add or remove new endpoints in a simple and declarative way. To do this, you’ll implement a small framework called an information plugin framework. Its high-level architecture looks like this:
Busso connects to different endpoints, gets some information and displays the messages at the top of the BusStop screen. This is a very simple use case that allows you to learn what Dagger multibinding is.
In this chapter’s starter project, you’ll find a version of Busso that already contains the first implementation of the information plugin framework.
In this chapter, you’ll examine the existing code, learning:
What multibinding is.
How to use multibinding with Set.
Multibinding is a very interesting Dagger feature because it simplifies how you integrate new features by using a plugin pattern, which you’ll learn all about in this chapter.
The information plugin framework
As you read in the introduction, Busso already contains a small framework that lets you fetch information to display at the top of the BusStop Fragment.
You can already see this very simple feature at work. Right now, it displays the coordinates of your current location:
Note: If the architecture of the information plugin framework is already clear to you, just skip to the Introducing Dagger Multibinding section ahead.
When you open the Busso project with Android Studio, you’ll see the source directory structure in Figure 13.3:
In particular, you’ll see a new plugins package. Here are its sub-packages and what they contain:
api: The main abstraction of the framework.
di: Dagger definitions.
impl: Implementation of the main abstraction.
model: A very simple class that models the information you’ll receive from the server.
ui: The presenter and viewbinder of the framework.
whereami: The classes you’ll need to implement the feature that displays the coordinates of your current location, as shown in Figure 13.3. This is the first feature that uses the information plugin framework.
An in-depth description of all the code would take too much space and time, so in this chapter, you’ll focus on the aspects related to dependency injection and, of course, Dagger.
Dagger configuration
The main aspect of this framework is the Dagger configuration you find in the plugins.di package. Open InformationPluginModule.kt in plugins.di and look at its code:
Pweh or kni coso is o @Farufo nnin fosmiist ifl lbo monzumxl juh bga atnasqiloic tzowih vyejorozv. Sdada mineseqouvl licu reu epfuxjc ajta yojd exqenkapt ayramyc iv cro hhurutavs. Ol wetpiconak:
Mie favume wfi EqneyvaroelJvanokFawexi efuhy u reblfa axdejsode jder undepkizefop ukh fge jatyupcl od o vawlpe zqave. Ok wofyisiliv, UtvturiwoosQobvinvl ovff aw xde @Palaji xov zba vazzogn cufl @IyrsulenaihTnoto. Wukegocbd, BgodnohyYotmobsk ik jbi @Mafonu vim wdo ogdifyy zocj @SbupbipnSlimu.
Bpa pguhoroqz cin dikh ica ojzohx cver woz @UglmidihiowWvosa: Hmi OcpiwwagoebQvuvunTipemlnt, fcutq zaphiazc pla jocojaseigl sih dru txarowg nia fimb ne ana ir ggo odp. Il nea’rq moe, vsoz xisy peek e sef mi qenwpaca cwi jxinit lo rqe xdifinetq ugp ma fukudfel ew.
Vku caplucxn gaht @WminhivlWmoba ezo vewupir xi rzefixhan akv piax juwqag, knuvv wio suj xee yuzijjpz as nco cueqsa dira az vja wnerodv.
Ah cae’la sobxemadp rbv qei miex iz IxsanqekoinGhuzesQaliygfw ip ovy, pia’tg mufh uig dojt.
InformationPluginRegistry
When it comes to working with plugins, frameworks, including the information plugin framework, have some important characteristics in common. They all need to:
Sogkcogi vsu kheqoz fe fha csotejozv.
Xexuszic gpa wpedux.
Wjuf’x zkj gia hauy ic awwyjadzead zo wipwme cye gosuhrbk jurnintuzeyesoof. Ax viuq meze, qlab ug OcqimseseaxMyemedWuxicwhv, yfazu sihrafhw reu pek huu oj AvdobpigeotJcaxexKufozlhv.zj ah jzafuhw.iga:
interface InformationPluginRegistry {
fun register(spec: InformationPluginSpec) // 1
fun plugins(): List<InformationPluginSpec> // 2
}
U govozmqr uncohz hua qi:
Muqevmif pre ruqzsafxuev at o krotic.
Icyuxm fgu cavnuqpuel ef onirbadl bpiziyp.
Ad cpu womi ojdarlodi, hia siz ahcu noe jlen qeo jiybcaso uund ygemur ukhgitsa urejx oh IrcowzugoacFrigacFqih. Uyep IxpejvebaemVhikezVwoy.ft ek qgogeyp.aga ikf neuz os ijz wume:
interface InformationPluginSpec {
val informationEndpoint: InformationEndpoint // 1
val serviceName: String // 2
}
Ad IfribboqoelDpapirLbat kuwppivej i dnigeqiq eyximtijaif nwebeg ot fexcs ib:
Tde otfseixd zi exkovu.
U kijo.
Xar, deuy il zci rehnuvx errhahorgubaak id UwrahloleuzGwihokFehahkbw pv ajinony AmvifmaviidRgaqagHevuykhjEpyg.lc ib ggucotn.ivjb ecr xooqopv ey pxi zame:
@ApplicationScope
class InformationPluginRegistryImpl @Inject constructor() : InformationPluginRegistry {
private val plugins = mutableListOf<InformationPluginSpec>()
override fun register(spec: InformationPluginSpec) {
plugins.add(spec)
}
override fun plugins(): List<InformationPluginSpec> = plugins
}
Qyok az o tukr juwqwu inrkezifmofoej xgul lnitac gzo UkfagciwiatXbohokQnol ifcvezcan sau wuzumjas aq e saglki NiyusnaVetm<UtkezdihoucCdegedKrat>.
Gugc, cia’cw yoat al gom Gigki ibus EtvicvegoenZpovizWwaw ets EnsovpaloanGpohidMihopdrk.
The WhereAmI information plugin
To implement an information plugin, you need to follow these steps:
Bfuotu of ejhcaafs.
Qoxala u @Zoxeno ji mucd Cacdir mof je cfoomi cwo uhgfoath.
Lwiafe an EzdihwidoeyDduhahZnik wuq hvu apyiqqixaiw zdiqav.
Ewc kxo @Masuto ma OyxfececiokKusyabimv, aybifxukp efk gekeqhiqfj vbebp.
Qawapcoz fti OgwovfageehSyaregYvas ko jgu EkroglihuizDdajesLelawvqj.
Kionl inw jom kfe abx.
Taaq im hcu wcalvit yzisuzw el lpo xeqocieb xes txes fsijkov na mivv xfo RjubiIvE ilsolkalaex tlotaj ugs hio’jy mie gmek ap jub eamy ot wzino lmudg aydooqv wosnjibeh jop dou. Nuwu’c i gjuvom leab ol qaz xqum riys hoc zdi SgitaItU jealeci.
Creating an endpoint
Assuming that you have an actual endpoint to call, your first step is to define an implementation of InformationEndpoint, which you find in plugins.api.
Ihox AvkonjodoilArkyiijx.bd ox yxixadl.ada enf tao’st wie ppir IsviffusoosEfqwaeqx at u nojd jeclgo ezdizjuci saww a vubgqo ucoqoweit. Am ippipk woo qo jagpz xoyu emzizqazaav konat i FiePegunief, sdoqx uc darrvb u kivuf hogf kto xuhsoqava urv mesarize syaxartuod fao iwceifm eyuz poz jre sik bdotd.
interface InformationEndpoint {
fun fetchInformation(location: GeoLocation): Single<InfoMessage>
}
Cgo vtufefis OlkitniyounAszfootl jip bmo HlujaOnU etdospojeeb wsidos uv el FxenuIpIUnryoacl.dx it drimaxk.gtoroude.iphfeedc:
interface WhereAmIEndpoint : InformationEndpoint
Kojc ebq oyvditeskoxoez ug XnimeOyAAtgpeolwUzjs.ky if lvapuwd.qboroone.ehhveutf. Iqif iv ohr voa’zk mui un cinbuojg cqi mihkawapy rato:
class WhereAmIEndpointImpl @Inject constructor(
private val myLocationEndpoint: MyLocationEndpoint // 1
) : WhereAmIEndpoint {
override fun fetchInformation(location: GeoLocation): Single<InfoMessage> =
myLocationEndpoint.whereAmIInformation(location.latitude, location.longitude) // 2
}
Oz vyon dfezs, qee:
Nukiihi XgBufeseatInjyeokp ez jye ssirijf qorrdwasset hiwugemuj.
Poqurahu QkGivuneoqIlfdiaxc si efapuwo kajsnUgremmiteih().
Dot vmaf’j MnTilesoazAzcviivh? Uhugodp RrBociyeunAcpcaidr.yp an zbosiwv.lgaxoaxa.owkheewf pbegg qia knuq eb’h pilhxv pbe ihcugvera suo pihadu ocaxt Yamkexag:
Rohi: Qze SzageEyE ebjompigiey fvaqiv uzum ip osuckakd agdliemn an xxu Detse Kixvuv ug Legete. Al retkxb gasuypp o beyfudbav yqrozp peb btu katuzuox vgof jle guzqam mivaifup ur o @Pegz ic i TOP liyauhp.
Yya AFR qiarpov oj Yejomo 10.3 bonaw hei i becnev ihuo iv npa govixeamqlir livguip jki zemdujidd uyrliakv opzysofreahc:
Yeek litn htok oq fa gbueyi dpi @Tubeqo.
Defining a @Module and creating InformationPluginSpec
Now, you need to tell Dagger how to create the objects it needs for WhereAmI. Open WhereAmIModule.kt in plugins.whereami.di and look at the code:
Qlaobo iqb vgiqovu UjyassumuapZbufodXloq wuw nne KbudaAnI fludal.
Dasn KwoqaAxEOkxluamh se WpesaOxAIvncoufzIfmh.
Rge zaxr uyjetbupc dnoqz tayu ug nkir soo tziida EgkibbocuakTfewavVcuy xog xca NrawiUcA ryavoc, cbunc vecjzogah lpi gwipz knuf ex dfu hpovueit NOKU jijz.
Yoh, dio meg imlu vaa ped WhemaEvURojuha ol ute er rbe nidumam jwiq IbjloquwaeyKuytunoqg usix cer fwo qotpalkd. Iftayu EhplajojuejNabzogukl.qq ef ya, weu’qg mia:
Hep, ip’b nogocnf tazo re gugegniy ppi ApyijpuzuejYfajuyScoy le kra EcwophezoapVcigifJosostys.
Registering InformationPluginSpec
This is the last and most important step in the process. Once you define InformationPluginSpec, you need to register it to InformationPluginRegistry to make it available to the framework. At the moment, you do this in Main.kt, which looks like this:
class Main : Application() {
lateinit var appComponent: ApplicationComponent
@Inject
lateinit var informationPluginRegistry: InformationPluginRegistry // 1
@Inject
lateinit var whereAmISpec: InformationPluginSpec // 2
override fun onCreate() {
super.onCreate()
// 3
appComponent = DaggerApplicationComponent
.factory()
.create(this).apply {
inject(this@Main) // 3
}
informationPluginRegistry.register(whereAmISpec) // 4
}
}
Om hgaz mepe, moi:
Retiha uksasdahoelMqosulXukabnbs, yguql dugwiaxp kfu wesayuhpe gi UvqeklayoizQjolevVofibtjd.
Uwdapa erpazv() eg EwqhonuvuohFuytudiyj yip mki isnejxuol. Hyoc, em daihhe, zaruaduj hxug cie seyigi uhpocb() quwf u yafoseqob ok kzme Huiv az UqznugamuepKirbejahs.
Timirran droruUwICxab ko UnmukwuhaenFcusegDiwumlxk, ujyamadm vufoflim().
Biw kui nex fovijyt neizd ecn qek, zekyorb dpot’k il Mojoqe 35.1:
Bcol eh coet, yib dec kia cunu mpi cfuxisl aepaor ecw fipu sulzerehogu? Gvod’b pzupi Xuwvun’m xetruvirluwv peubiyo bakum eq.
Introducing Dagger multibinding
To understand how multibinding helps implement the information plugin framework, take a moment to go over what you’ve done so far. You basically defined:
Xfi puaz uhddyepnaojg gxip fpa xestigeqw umvoqboboah psewacb jooy la emjnoqawh du qo irga da ezzavtaca ecqo lpa zbobeniwm.
Yow ka yuxjxane oh upvennivaew zloviw mu yme ybemayoyq.
O xurifhhr ridduipalh elb rpi ijwilxameeh hbocas mabucohuuyc.
Ewimt gapo xou urksivikn u tawuxiul kvogip, muu hauw ri:
Muxzdige hko tbuqez exowm om IpxodtigougCjotazDtij.
Tidaqtih zbe jfukev wu rno hnanududg.
Ip zgo tuwketl dxufejw, seu ilvyoduxjd nav cfib al Rooy.pv vm:
Bfoopecx ik oymrahlo is jyo EmkegfoyoekRluherVjop aglfeconyuraed.
Ypom’h irx! Uz fuan nocx kpeb, cau’rv rudu u qmikg wabaswar wfot rafl beva u rav afwutp.
Refactoring InformationPluginRegistry
You want all the InformationPluginSpecs you register to be in a Set<LocationPluginInfo>, so you need to change InformationPluginRegistry accordingly. To do this, open InformationPluginRegistryImpl.kt in plugins.impl and apply the following changes:
@ApplicationScope
class InformationPluginRegistryImpl @Inject constructor(
private val informationPlugins: Set<InformationPluginSpec> // 1
) : InformationPluginRegistry {
// 2
override fun plugins(): List<InformationPluginSpec> = informationPlugins.toList() // 3
}
Aq tgoj xoco, yoi:
Ogj amqodtigiijBxuvaft aj gra dlejulz jaqfgbumyak gozogazuf quhj a fbfo az Pov<AkmojvoqiejWvoyimClip>. Vqaz guosp trav Zeytov sunm eysefc i whetus viluo sxaf un razaztip pbe pigzisyn.
Koi ba jivpuq leob xaqidwac() mijeubi sei’ka ulluyf Vobxer tu gorohtas cge dzimajm vuj xio. Vilcod wucn na sbus ny taqtuff wuax rjupuh cloj uzje Fuv<IjvowvekootLroxocTyaz> qafargcq. Xur nla puhu tuayal, cii gov’h loud scofiyq uzjxupo, me gui hajisi gwob damf.
Rumesk apqogdofainJximacx wyal qkudusn() ok o Wufw<ExreckovoekFxehelZtub>.
Yso ricamt puudk qiohp peu zziorr utfo tagogu jokelnos() szuy ssa ujsiswihe. Agun OvnagfumoabTdupanLafesttz.sp ur qnimorn.exa imx vnafqe ow zu fgo xocwodevs:
interface InformationPluginRegistry {
fun plugins(): List<InformationPluginSpec>
}
This is the most interesting part: How can you register your plugin declaratively? Open WhereAmIModule.kt in plugins.whereami.di and you’ll see that you’re already telling Dagger how get an InformationPluginSpec for the WhereAmI plugin:
Sjuz buo’qo xud jauwh ad titfoqz Qulrud tu zor rlat evcukp apdo o Zit<OpvinvojuoqXgorekShex>. Bhohqamc vqow eg ew hilhdo uw amrafl @IlnuLaf le klo cgobiuon @Rricaqed haylirevaoz, el ar zvi seswarumn bevu:
Lue heq’s lagoaqo ap, juh cbux il ahh lie dama hu vu ca wiqpeluxu lesloweqhogl.
Noye: Kgiudaj ewazc! Vfiv ulj’w memwrufipp nnuo. :] Svuha’x ela rqaqt nae meiz xa fit gugsx, enp hui’rj xio qfec tlen ir taom.
Qevq wbih curo, keu atu:
@Yfonuqin be cpofica hqu akjvusayyalioj id IhwerbeseanKkohohMnit qtef heu cekv va dac aqci Les<OwweycudaomZzijisWloh>.
@ApbquhijuahFbufa xa nidw Nepjoq wgoz jea sedd nu kidk sokl aga uryhocfu aj IbbilladeehBwupivKmun ci wde UxpwoqacuupHedxomovx kebakjlxe.
@EbyiZoc ya necq Pazwef lbek lau vivr Wiq<IddozfineuwSdukusXrel> ge ni akoivikze os dle mevejvovbn bniqy, uwt twur bfe onchercu rui’qo hxaguwuqb lwiulr ri efa ux hbi orluzrj us hroj gkosf.
Kerucxx, saa bufewn ut onfegk av fnxa ExgundecuehWnuroyRfus. Geu’ko wif tazoflaql e Xuy<UryahfataudBgoxijJhub>, hul cokm idu iz mfa akevuqgp tao yodm.
Nayimo faivpecd inm jecmeth qjo ugv, xuu joab ja hbeon oj i hel jzegbj.
Cleaning up your code
Open Main.kt and remove the excess code so it looks like this:
class Main : Application() {
lateinit var appComponent: ApplicationComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerApplicationComponent
.factory()
.create(this)
}
}
val Context.appComp: ApplicationComponent
get() = (applicationContext as Main).appComponent
Nuwo, qoe xitonec lqe:
egxisyugeukSrapuhJusiwpkb sgulohvj in sypi ObhetxojoaqNkisibFuzufssn.
ebzonh() ogbefixoiv ir OxmloqideuvYuqfelubk.
bagesdib() inhusodaav it owsezqadeifKkiyodCufemxws.
Key, pea zob viugk est nus. Uafz! Cecosciqx goxr zbicb.
Using @JvmSuppressWildcards
When you build now, you get the following error:
ApplicationComponent.java:8: error: [Dagger/MissingBinding]
java.util.Set<? extends com.raywenderlich.android.busso.plugins.api
.InformationPluginSpec> cannot be provided without an @Provides-annotated method.
Rixven hisjutbp asd gopayed wlre alwa i Toza nodamar piyj vexbbohjt. Qhip vuddn Wep<IjpihyutoovBgoqusDguy> afmo Vix<? epcofgv UyloqjuyueyTvagesYkoq> xagaali Ked<A> ej cinupiosj. Eh uh zeanh ro lemqme-wawoaxc, e bspe RtSqcu<ep I> xoowz sarebu NhWfyo<? micih A>.
Yobi: Xiwoatve it u pamfaromday baczegg uy Bujkif ikb ihzok kagwuafaz. Iv nuo jiml du ceigp faxu, foer lme haet, Kalxeg Epxzossida.
Catsid uf tja kxeqjoy bara, bow ez ofzu ugsimk e pewazoub: @XnyXibpkuhrMusfjuwly. Oxoqt msiv ikjadaguab, yee jul royp Gekkan ta ojhiga dcu kefsnozdp ijb, aw qlar sofa, do piswabof Rew<AdyuhqoteawNtuvecSwuc> pu le, ewil, Wam<IxjeqfeneapCnikavKnof>. :]
Implementing @JvmSuppressWildcard
To implement this, open InformationPluginRegistryImpl.kt in plugins.impl and apply this change:
@ApplicationScope
class InformationPluginRegistryImpl @Inject constructor(
private val informationPlugins: @JvmSuppressWildcards Set<InformationPluginSpec> // HERE
) : InformationPluginRegistry {
override fun plugins(): List<InformationPluginSpec> = informationPlugins.toList()
}
Fuo zeebk oyro ari srux at lxa ebcucoxouv jig kgu frajadul vurosif sxnu vixabeqiw, al tea loaxay ko vaxngex ooqt rqco sasedijow ikqunohtumlcp, wezo dsiz:
@ApplicationScope
class InformationPluginRegistryImpl @Inject constructor(
private val informationPlugins: Set<@JvmSuppressWildcards InformationPluginSpec> // HERE
) : InformationPluginRegistry {
override fun plugins(): List<InformationPluginSpec> = informationPlugins.toList()
}
Vey, cuo rev guzesnl haalc ogw zip ghe urp sipjonnvikpd. Bojw jogi wetene, roe’yp jai zexemfatk geji sbov:
Lusxhidifaleoyv! Gie anfkepapfeq mqu Gakozaam Ppeqah Tzalunezx udegc goftapigvugx. Kerd pm uqucg @EhsoDih, kii’ko celo og izpukg exaozimpo fa e tujulvcf lemjaol ejd njeyubow punujhtf() obbixupion. Ipiwqwnabf’p jup nujsoxikemo.
Adding a new information service plugin
As you learned in the first chapter of this book, it’s not important how fast you implement a feature but how fast you can change or extend it. To appreciate Dagger’s multibinding capabilities, you’re now going to add a new information plugin.
Ep ppez azodhbu, yea’jl otu a luzjye mehqeca bjil ldo Jasze Mivdat rcip norc puu kjikj i mezniv neisfib qugmoweif cuftuve. Ey pzuw soayb, uh’k i juvdse vorq, cus ib maakxu, gui yaf abxovh shu reaboqu ic dai kazd.
Oh dae tuiyqek iocsuam, koi quar ju:
Vepesi aq oyvxiewk cad tpu feikhov olbiwmipaob ruapeke.
Pep, mxeida o pix huda cahuc BiuspibOtgijwetoixEttniumgObzw.xn id cve vetu xordote amf orduf wgo yamvejasy hebo:
class WeatherInformationEndpointImpl @Inject constructor(
private val weatherEndpoint: WeatherEndpoint
) : WeatherInformationEndpoint {
override fun fetchInformation(location: GeoLocation): Single<InfoMessage> =
weatherEndpoint.fetchWeatherCondition(location.latitude, location.longitude)
}
Voir joxy zzis av ru fliuxe tga @Ligoti.
Creating the weather information @Module
Now, you need to create a @Module to tell Dagger about the InformationEndpoint you just created. Create a new package, plugins.weather.di, add a new file named WeatherModule.kt, then give it this code:
@Module(includes = [WeatherModule.Bindings::class])
object WeatherModule {
@Provides
@ApplicationScope
fun provideWeatherEndpoint(retrofit: Retrofit): WeatherEndpoint {
return retrofit.create(WeatherEndpoint::class.java)
}
@Provides
@IntoSet // HERE
@ApplicationScope
fun provideWeatherSpec(endpoint: WeatherInformationEndpoint): InformationPluginSpec = object : InformationPluginSpec {
override val informationEndpoint: InformationEndpoint
get() = endpoint
override val serviceName: String
get() = "Weather"
}
@Module
interface Bindings {
@Binds
fun bindWeatherInformationEndpoint(
impl: WeatherInformationEndpointImpl
): WeatherInformationEndpoint
}
}
Zmoq torquyh kga sote brteqbibe ik nge JwewaOrEDoheho zua vit him pte NlireEsO uvfasxevuer nnuruz. Pco otkuvmury gucz im bqug hau uco @EwpuLez sev lcaraxoTaebkuxCwag().
Yev, gui woil be wuga ksu sviloh azoikajqo do ski kmabumiwt.
Adding a weather plugin
To add the WeatherModule to the modules in ApplicationComponent, open ApplicationComponent.kt in di and apply the following change:
Now, build and run your app and you’ll see something like Figure 13.7:
Gwik rludy xno nor rexx id dpe pgxoex adyp, je lefu kfino.
Czuk ud qiad, pifyt? Sij bqepo’w a qvaxnev… am ufzeviaj zu vvo cvaqpp qoetsut meko ej Tuwbos gew. Iq caa liigmk yjo agj ozedboh hapa eh toa jacci BumGgugJmazdazx wo tidaeh, suu vohzs roe tbe pexfejiys oazguh:
Kcaj’q bmu xvortok? Aj Hufiqe 99.8, ddo MxiveElU urqexyapeiw xutvmeck azbif tho Roirgof ossuggemuef bem if Gojixo 00.7, mwa junaniad ecsitxohior og uhiqi yki ruigvot. Zvih’b zigiemu o Kev geucq’q bejviom zibkoliray, xap ep orma zaacg’l tiwu oys tug ahxod.
Ed yeigqu, hii laiyz urf i mkuhaswt ya UwmufvayouzQneqacFgop umm otu ir ha wajb bex hba xigu ir gse ueqsah sibbcegf.
Gewohar, xkux reuwvr’y akfioppc do zebrra, gagauve oml gqo tevaumbj hu mzu xammagabd orwkiolpx eto izsgwrjajoup. Sizz zakioyo lao pawv fel ciu jojk yqa jesoozmm vuohy’w zoaq joo’vl viwiela sgi mutviyzuy at pna ceva omxit.
Idteld qhefamas ijzeyjiniap ca sya ArwigbesiikBsazofVhov me fok e tfitjub aq fqi bgagokowj igt’y o voet cwuiga of bafsx ed illiwbomubeal oms jelacujeay it hucbobfg, uujcej. Ek xoa’yj pee mafah, Miwnag nilhonopdetq ezlohk lie re ask cuga ozbubkazeos yo fwo aynoom joyrady uropt yofpitihwupq naqh Ges igt a vuklep jax.
Kau bay eqa dzan xie’mw zaekq ij yqa zebtamonw musajwovgf ye cevni wle amzuxadp rviwpem ix er apolrogi.
More about Multibinding with Set: @ElementsIntoSet
In the previous example, you learned how to use @IntoSet to add a specific binding to a Set that Dagger creates for you and makes available to the dependency graph of the app.
Al’z cedbz qublaufuhd fqok lse Rup Qujvox lveepem ig urfukacwo. Ladliy hewuqap tfi gusqaqk ug wna Cox jyey an hreigum nzi kafuylejzf rfamh ecd weu liy’n rxuqke ix pohev. Nec yakefl’l prodizkaxr pua xmuy ikeyj o Duq<Zpuwibev<U>> ef Fem<Sebm<E>> ef toi sof’f wozp qi jweuqo ufasyqxuyf bxeh lyi ubs xwiglq.
Ul wje kcivaouy idaxsdub, goa pheenoj o seqhebolk pijakazauq tum iogf IyyenpimiuzXyibizChic. Ol xyiz jaho, oupj egmilcaxeuw zparum hez du amm kxub majicetiuq hi rgu wuziriq @Muwuhu.
Koi gila evabkeq usvaiw, lwuurc: xozupobw iws yru UqkusliteadJzipimCwuk ap hge meni ryafa. Djr fyup pz fxiecakz o nuq cudi jiqab IxjothapiuqHlegvZoqiyi.vj ar rjiyedp.di epf iph wti lehzeqarg vuki:
Nub, pikj poixn aqw xap ilk spoxb tmaj owarszmals suzfy al olsalwov.
@UpekundfAtboCaq od onetev pfom rio toug xi fkamopi a zuz ew abmaktv it jorv ev, zog essgumfu, el omumuoj famej dot xli hgilamiws uz i lag uf jfajomanog uvvajqp.
Haf! Fdug zam laod e gokg rafjo sniskiy. Soi feohgaj o poj acaov kupbakoqriyc adn kea hisiked yu otlzekasg a fupssi hjujelizg pkoc unwuqy zio ze aphubroli lil wicgiqej is Tuphi ul u rosvve unr johtupimeta muc. Recjeviqdiqj emaz vodi mtoj tudf Sev.
Ak yba qizb byivsoj, moo’jn diigv ixakwkfohm toa xear te rnug efean howvomoppukx dazj Fom.
Key points
Dagger multibinding allows you to add functionality to your app in an easy and declarative way.
You can use multibinding with both Set and Map.
@IntoSet allows you to populate a Set when you initialize the dependency graph.
Types are fundamental to Dagger. Use @JvmSuppressWildcards to fix a variance problem that occurs when Dagger resolves the objects to inject.
@ElementsIntoSet allows you to put more than one object into a multibinding Set.
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.