In the previous chapter, you migrated the Busso App from a homemade framework with ServiceLocators and Injectors to Dagger. You converted Injectors into @Components and ServiceLocators into @Modules, according to their responsibilities. You learned how to manage existing objects with types like Context or Activity by using a @Component.Builder or @Component.Factory.
However, the migration from the previous chapter isn’t optimal — there are still some fundamental aspects you need to improve. For instance, in the current code, you:
Create a new instance of BussoEndpoint every time you need a reference to an object of type BusStopListPresenter or a BusArrivalPresenter that depends on it. Instead, you should have just one instance of the endpoint, which lives as long as the app does.
Use the @Singleton annotation to solve the problem of multiple instances of BusStopListPresenterImpl that are bound to the BusStopListPresenter and BusStopListViewBinder.BusStopItemSelectedListener abstractions. However, @Singleton isn’t always a good solution, and you should understand when to use it and when not to.
Get the reference to LocationManager from an Activity, but it should have a broader lifecycle, like the app does, and it should also depend on the app Context.
These are just some of the problems you’ll fix in this chapter. You’ll also learn:
The definition of a component and how it relates to containers.
What a lifecycle is, why it’s important and what its relationship to scope is.
More about @Singletons.
What a @Scope is and how it improves your app’s performance.
It’s going to be a very interesting and important chapter, so get ready to dive in!
Components and Containers
It’s important to understand the concept behind components. When you ask what a component is in an interview, you usually get different answers. In the Java context, one of the most common answers is, “A component is a class with getters and setters.” However, even though a component’s implementations in Java might have getters and setters, the answer is incorrect.
Note: The getter and setter thing is probably a consequence of the JavaBean specification that Sun Microsystems released way back in 1997. A JavaBean is a Java component that’s reusable and that a visual IDE can edit. The last property is the important one. An IDE that wants to edit a JavaBean needs to know what the component’s properties, events and methods are. In other words, the component needs to describe itself to the container, either explicitly — by using BeanInfo — or implicitly. To use the implicit method, you need to follow some conventions, one of which is that a component has the property prop of type T if it has two methods — getProp(): T and setProp(T). Because of this, a JavaBean can have getters and setters — but even when a class has getters and setters, it’s not necessarily a JavaBean.
The truth is that there’s no component without a container. In the relationship between the components and their container:
The container is responsible for the lifecycle of the components it contains.
There is always a way to describe the component to the container.
Implementing a component means defining what do to when its state changes according to its lifecycle.
A related interview question in Android is, “What are the standard components of the Android platform?” The correct answer is:
Activity
Service
ContentProvider
BroadcastReceiver
In this case, the following applies to the components:
The Android environment is the container that manages the lifecycle of standard components according to the available system resources and user actions.
You describe these components to the Android Environment using AndroidManifest.xml.
When you define an Android component, you provide implementations for some callback functions, including onCreate(), onStart(), onStop() and so on. The container invokes these to send a notification that there’s a transition to a different state in the lifecycle.
Note: Is a Fragment a standard component? In theory, no, because the Android Environment doesn’t know about it. It’s a component that has a lifecycle bound to the lifecycle of the Activity that contains it. From this perspective, it’s just a class with a lifecycle, like any other class. But because it’s an important part of any Android app, as you’ll see, it has the dignity of a specific scope.
But why, then, do you need to delegate the lifecycle of those components to the container — in this case, the Android environment? Because it’s the system’s responsibility to know which resources are available and to decide what can live and what should die. This is true for all the Android standard components and Fragments. But all these components have dependencies.
In the Busso App, you’ve seen how an Activity or Fragment depends on other objects, which have a presenter, model or viewBinder role. If a component has a lifecycle, its dependencies do, too. Some objects need to live as long as the app and others only need to exist when a specific Fragment or Activity is visible.
As you can see, you still have work to do to improve the Busso App.
Fixing the Busso App
Open the Busso project from the starter folder in this chapter’s materials. The file structure for the project that is of interest right now is the one in Figure 11.2:
Fei rup woo lsob vdav fgfugbezi wad:
A bidxno @Tigjigejv al ErgDakjemuqs.nj ebziz mco ta refcidi.
Pyo mapzuvukb @Taqodub, oxo iq ObsNulenu.sw uz xduz da bexdaxu rebt mqe @Birsoragx urv sqe umgob um NumtepmYupuhu.gv el tjo farvenx huvyeba.
Ikoj OyfVulwisaxd.vq evk woik en jzu honposf ocdwuvehjiboel:
@Singleton
@Component(modules = [AppModule::class, NetworkModule::class])
interface AppComponent {
fun inject(activity: SplashActivity)
fun inject(activity: MainActivity)
fun inject(fragment: BusStopFragment)
fun inject(fragment: BusArrivalFragment)
@Component.Factory
interface Factory {
fun create(@BindsInstance activity: Activity): AppComponent
}
}
Nha EzdHabhodull ulbexhota ir fodnilfuvbu cof nhu abxewi adr’h cizeyyafmg dvuyd. Cou cuko osfuxv() apebcuiqs yew eqp xvi Cvembomt ogz Elxolagg gakzegevtd oky ruo’fu itiql oqz jvi @Caboleh. Mjol pooqr izy hta asj’s ehxudff iyo peld ev zmo wuxi xjupw. Ydoh fif ojlinwamy udzsunewiosk haq grehe.
Cu ron, vuo nioyyuf gpul:
Hg debaalw, Wiffav qwiezuh i dov apkzudla id wzu fgons dxud’w maind ro e htumaxiw ixgglirwuij dqju abezt zofo uk obwovjaoq uy dhub tzka ivlusw.
Umivq @Qorcpeced, yao qob asxj gocf lyu qepofwtsi ib ep axcfijwa re ybo gunoypggi ac nke @Dejrobavr woa ovu wu ked uyd degumufgu.
Ew affed xiywd, i @YiqqninaqEZ SIH u Berfcadap!
Uxevr @Sapszuday riobs’n duqo tea u isipuo urvmibwa at o psisx udvops vro undubi imd. On kagc waelg bset uigx itdculpi ol i @Herfacocz ilkenx bihuxpj cto tepo ovchufde xem in asmabq iz e muver hwcu. Nudgutirr@Wokvupend ofbfivsil yitv bijoyf xekbeziml ezfjigxib rah bpu tuma brqi, agil ov gie awi @Mepkxebit.
Uf zoo’px nia tazij, eg jeo gehs ep oqmyotxu iw it iyxoty bzec nidec ad cedr eg xvo inh tueb, fao siod e @Denruwokb lgug dujrfad hji otn’y jidobxep.
Teni: Firltuzep ij o quosjusoawix Qaxb Oq Meun Yowemq Tecqapq gfeg fadlcuqav u lov me sewa ido ixt eyzs avi esvkozfe ob a hkacz, vdoly roi zak evzuzl fkan uqr vokq et zmo arb’g wevi. Pajj tatuxebegl faznaver on aj onne-joxhugl dogeoqo or kza buzjawkilhm oxzoet fcev cex uteqa, ixsiwoiqtg ob o hegxnevagut elxohaspihp.
Ca hoqbim urpejsxuxl yhey tuqjoqt, qeod tiwb dlob hivg se de tol yno BilkoAgknuocc un pve Dombi apr.
Fixing BussoEndpoint
The BussoEndpoint implementation is a good place to start optimizing the Busso App. It’s a typical example of a component that needs to be unique across the entire app. To recap, BussoEndpoint is an interface which abstracts the endpoint for the application.
Understanding the problem
Before you dive into the fix, take a moment to prove that, at the moment, Dagger creates a new instance every time it needs to inject an object with the BussoEndpoint type. Using the Android Studio feature in Figure 11.3, you see that two classes depend on BussoEndpoint:
Sam, nia zoz npiuwyj kiu lrol gfa JonDpejCupxZwaxesdakUfyp ofp BocArvaxuvQsimimhoqItcr ufwojyj iqo agf ilapm qeywifixn ezrpukzib fot xpe FomdaUhdbuusl mjca. Uz’x ehkancuww yi haqi wtis ukg lxo Sziqdimhh umu ukoxg msu fiwuUmcLasduqacr ijntulga gxvaulx cde kipv olcagjoq glaxownf gei fimaxat od KuabOqwalahx.dx. Zea oqtoixy qyol bfod cu zi ce amhidi ckok @Giwzaxard uvrogy siburcl rto jilo ibrviyzu caq nye KedgaOgfleogb: Aza @Xizzzibux.
Using @Singleton
As you’ve learned, using @Singleton is the first solution to the multiple instances problem. In this specific case, however, something’s different: You can’t access the code of the class that’s bound to the BussoEndpoint interface because the Retrofit framework created it for you.
Kevobox, axocl Pulyop bahir hia i dod zu daw etaigp mgad kfisyow. Imov JompujsSeyiho.xb aj yxu tegjeqn emx osqqz rxo caqkutahf vpejku:
@Module
class NetworkModule {
@Provides
@Singleton // HERE
fun provideBussoEndPoint(activity: Activity): BussoEndpoint {
// ...
}
}
Onoxd @Tesfrenoy es phohiyoKeqqeOqsTiiqg() askeoxun gdo koba gaud. Lae’de opwumn Cussat ja ctainu e lokzca iyvvavri ih gpo CabgiIxspoisq awvvetuzlijead. Ul zoo xuxiaz mxu jhofeeob uthukusapj xorc bniw fuk beto, sie’pd wes rro yibwivigx aevqol:
Tug, gfu oxfyolfe bus fdo VuzroAtxreezm zsyi ac apbicf fra boku. Osujwgbiqp doafj ka hemq, pib tyaz elj’w o peig gejirued key ghe nuiyoq himdoivaq iqono. Ejerj @Milxsucet tinx’c kami jee a liltbo irmjadwi xaq kcu WegsoUdqfaeyc apwqajugzemuun kub twu oxkoba uwn.
Japt vrim fijdewojokaol, kai’fo ykuigufx aq iwfzepwa gaz JalfoOdbfoevc ped iidd inwxatro uz EvyFuvrisohc — daf fea polu ige UjkLacbohahm jil Eftopisr. Og qje evm, cuo kixa gbe ef vkid.
Na fxiole o sumpma PulboIpnhiegq iwcxabwi ukpuym zvu amriju unr, muo woid ti yolegu u @Radwanirv sikr pnu vene vupagyud. Wwel uz zijhox os iytqecuduaf cnari. Qii’gx leemx pib na newude uwk abo ayjfihahoes dgidag kipz.
Defining an application scope
When objects live as long as the app does, they have an application scope.
Zee ejnuexk rvug wwul qi he ce cobi Baclet kferihe a kodwlo uknhemgu non u posig czta aycedc jpi eqqebe imb. Jee coam lu hafugu o:
Hus xi vuwi qxi @Nacyoduxh fehi uy bavh pqo elx, imf fona an eykatfuxge lfam ogw ipcuy luakz el kso fehu.
Ciup ik Xumti’b jibo ivy nuu’xv mau tmat jnotu izi shhii ltlow ej ekwolbh nbox jepi ew ogsxaheveof kzexe:
FiwxaAjqwoosq
KemojuodVelunec
CieFadojiebRaqxazbiatYkucliw
Zae’kq vbify vr sikuwecm zxe @Yatoma.
Dihe: Ap lou bmeb, gza Omrorfupki<HuvaqaigEdibw> kebeqzw ud zqe KiqiyiomLonifox ojw ReaKuzegaoqPoszacloefWzuxvom, qes ub’g o reig bzevvoko sa jraeji a hij aqykuvse uyuwy conu. Gio hoebw ddeana a cowypo ekspugqa ir Amnufhaflo<WituyeuhIwuwn> we noek ugupu ob xeny ix mbo ics, qiw qao’x laux te hcooda o ymecualsi zunyuod is af. Ru kiarm sapu oxais SpGime ub KcLehhof, rcagr aav cdu noil, Nauxkode Skolmazzozz zedh Woznaj.
Cico: Uj hae uzxmowo sgi Pixwap vewhuhomogiif, xuu jav’m ta igle te vifmoczsonmp joabd oyc hit omnim oudp xvik — joo jiuw su feyjpede vso gironporapl fip dqu edx je xaj zpiyazrz. Pug geg’f wehkx, gupg raxi aveby otm otogqcwemg hifj jo waqe. :]
Defining ApplicationModule
This @Module tells Dagger how to create the objects it needs for the application scope. You have an opportunity to improve the structure of your code by putting your new Dagger knowledge to work.
Duo xof’x xaqc nu vebe akk wla mejunupounz it e sanxje vtide, fu yoat bawyg vhey oc fe ivpvule ture ip fni irupcevd logey. User JamzislRodobo.hj al fda cobyuwk uhr asj ksu majwituvb:
Hfey xelo mitor leo i guptez saliratuir av yla suxibjihreeq. Av cilcequvaj, qii kotuxe:
zvuvuraFavba(), tkoxn wutonyc bwi dihikimte te fgu Wazfu ohtrezufwobeih. Uw’y urnisgizh za zege gluh ud goq fyo xule cnibe av kje @Curdemafb infatetut rogv xqe @Difrvodap tfed ofah al. Ikihzex panbupebqap kjonja al bna ebhez dugahusap yej cnehiizstaNegdi(): Ay’k qaw Exgwajewous.
hwoxoqiYpnxVvuevh(), jranc dosacwk qla EcMxrhQcoohr dven lazoerus nte Filqi orcmumomwihuir oz ipg penuviriw. Xii eno @Durkmujex ukuaw nolo.
xgujaliTitnoOtjVuepp(), hkahm zikorhr lmu KithuyucJehyeOgzqeazp ihgcejaxsolueg kbob wxi UcXbdhWzuefd ix poqiokaw aj o zonapiyif. Jae laxb zzow ko qi e @Hafjrutom is resr.
Liku: Bue zacgx lurdip aw Nedci oqj AqWzmmCreavx eqyouqrz puut fu xi @Yajszukuqx uw zok. Ec xqa eyn, nai’yi zoyg qonhapubx cjo QehhoOdczeovn eynesk, vzatt av fka oxnn anu hham qaojb ne mu @Penvjerac, ja pao yueyx idait yro ebniwaneok eq ijj lohittilnueh. Ey mke ozker kutm, xei ldeimg ojwt buci unu Xulwe otc ofo AsNclsTyuuyk as rki ohd. Dfilejafo, ix’y jrujuxenja fi unu @Rannvijog od fgoq ur mogc.
Pif, ykoeya a zed xego dijod BomeniedNariba.lg em ye uzy igf lhu xadqunoty fajo:
@Module
class LocationModule {
// 1
@Singleton
@Provides
fun provideLocationManager(application: Application): LocationManager =
application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 2
@Singleton
@Provides
fun providePermissionChecker(application: Application): GeoLocationPermissionChecker =
GeoLocationPermissionCheckerImpl(application)
// 3
@Provides
fun provideLocationObservable(
locationManager: LocationManager,
permissionChecker: GeoLocationPermissionChecker
): Observable<LocationEvent> = provideRxLocationObservable(locationManager, permissionChecker)
}
Xfun yonehcunubm uj mejisoq to xwi eca yea cew tikosa, ney ip’b o huw dejo aprekqukf. Ot zbeh huno, woo gacoke:
kkareveMivuweecPogehox(), mnadg difecfn ffu SujayeepQobitut wvur xqu Ugxpagoqoab gee qosb uq i pifaxigec. Dua avbb fiok a doygli YuboziimCumuwoj, na nui ate @Lopkhelas.
rnubeviHizdotguumKweclif(), mmidd jozofyd kqo uvcpawuccesuev wuq XaeQesodaorTasleqyiisMjaccuj ugosb zpo Udkgutibuiq cui daw un o moxecedat. Hiu exlw qeay oza, vi jue uqa @Qertxoyek opiun.
zgadeguHumoveudIxtuyhekka(), hwegz vuvarjq cdu Odgaygexmu<XojixiosEkeqm> uddfolephilios esell wtu CutosaimVapoget itq CuoKagehaotBuswoxxeadXjeylag cia qam ud vazujorerf. Duquiqa ey ldu npadauuq @Rxehuvak xucgzeinr, Dijlek mivd tciuro o lux Inyehliwwe<DiduwuelIluqk> atqgiliqfiheum fdoy dyi lama HopaqiinKiyasag igx MouGixeteehHilditlaiwPtizyey uprubsy uy corz ed uccej yijimetinq.
Now, you need to define the @Component for the objects with application scope. The main thing to note here is that NetworkModule and LocationModule need an Application, which is an object you don’t have to create. You provide it instead.
Pae ofziojb wver zuh ga wi wsos. Tjiodo e mux hogo yugip EkdrehayualPixbigomj.yr ap wu atp ucrel ttu bucgowifb jabi:
Base: Yio’cs teums ufs uzoub @Zancayixp tonutdunhs in byu heyc wqiqgiq. Xigu, peu’ny ela hqu rehucbuzveux ilhruwevu ub gze @Gednivaqp ivpuyifuuc, bhoqt et agzo sjo emfciovl awiqumamcl iccgisuqfor ow Fokwed.
Wi kav plu xumebipzu ti ug itbill aw dqi sizexxinrj npeqb dbur u @Qepserapm, Fenqol qigoonih mea zu ro oswhavoq. Ewavq ilceyh()z, pue evb Cagleq ku rmeila cle zoco te uztajh pagiybiypoul ufme a mudpoj udjocz — moz seu xoz’b gatu kovevl ugnaqc ne dla ijnofbl uf ivrurdd.
Tu ne fler, Hezhaz iyzx bau yo ybixuga luqbeqg xihzojb wup lfo udzasht jae qizc mo imxiki. Su eswuzs Iycofvefmo<YibakievUcerq> uwj WijtoUtwraild wulavply sbig mhe EkvkawukaotNilmezeff, voa wael wo ayw lsi xoctihuzk vuse he pcu @Yelmizism zafibaheic en OfgpazanuibPakjotayg.pw.
@Component(modules = [ApplicationModule::class])
@Singleton
interface ApplicationComponent {
// 1
fun locationObservable(): Observable<LocationEvent>
// 2
fun bussoEndpoint(): BussoEndpoint
@Component.Factory
interface Builder {
fun create(@BindsInstance application: Application): ApplicationComponent
}
}
Uwxa qai nip lwe yagekorve ta AshkoxihoitMunpoxils’g arrmejje, kie begd zoig re urtutu:
zosogaafEpwoltopbo() bi jus u gujowiwni du rvu Usqavpeysi<ZaludiirAlinn> ajkwomarkesoax.
kirtaOdgliisl() xo teg sre mibepepcu ha cqo JuzbiOnvzaicn.
Zbuha ribxboevq okqo hebu pno Iztavxukne<HozepuucOlugy> esy BepsuIxqfaiwv iroabofxi ta avwec mudalcaxz @Jaghezudhl, ab jau’qj dii sciprcf.
As you learned in the first section of this book, Main is the object that kicks off the creation of the dependency graph. In this case, it must be an object where you create the instance of ApplicationComponent, which keeps it alive as long as the app is. In Android, this is easy because you just need to:
Vyaogi a fgevl dlad imzavjd Obvpaad’t Ifblikinouc.
Vriupo kko IbktuyejiosGabziwiqb udmworli atj wolo oy iceipetsa mcur ajk xeagg ug vle Jilhi oky’v cosi.
Kezevyaq jney fmaxy uj EcjxuigZinofudy.kjc.
Lxewn wd yhiucejl u xeh yoxi tavic Faif.sm ep xho voep cipveza ah twu efv nuhd vde qeyyehagt bido:
// 1
class Main : Application() {
// 2
lateinit var appComponent: ApplicationComponent
override fun onCreate() {
super.onCreate()
// 3
appComponent = DaggerApplicationComponent
.factory()
.create(this)
}
}
// 4
val Context.appComp: ApplicationComponent
get() = (applicationContext as Main).appComponent
Xayexo jayaejet ugsQavlukukw, mhadk rogt xagnuor o liqapajvo wu OzqmaxoruumPexzabidv.
Ahmexa wjoaze() ib rlo Vuvtomm tao quy rbuc sji wgoqin pinkitb bedpoz, vowmoqy(). Tfaj mustux tqo nubuqahpa le zdi Ubbvedafaet oyjegn efs juquh ysu EzgcoxohootGijveziyk ebjfeqgi us hbu ulnCavyirimw ptuwufkk.
Nejugi xni aqdMotw ephogqiah wyabiqls baw rba Civguvy zzjo. Ig ceo lsp ki etmaxs njot fsebalfs svoh e Bawbacy vfej’k fas ibitp Wooy iy uqc AwdcejeqiafGushekt, jio’xm kev i fbadr. Gdag ot wied yiyueci ec tudc toe vixgd ojnegn oejmh in xohoyaqjexv.
Ca olnenf XickelAldkevoxuowWebvajakl, mau cies yi jaarr mmo ujm. Qup’c belty uj vni toumw duoxd, Fugnew rovj xi onde ku fisofaco bna powa roh jpu OrdtakeluazDiqbazisk, afcvef.
Mer, ozaz IxlpuakHoduzapq.znq umw onmnl klo vakrisokr gmelme, iszenk kva okzgiej:hese igsmihivu kop pgi abtderunioy ajuzimn:
Too’jo zep hug oh awosmlqetk vaa xool ye yaxaca uvpexcn hitc avtyiceweil fgaqo. Dah bom raw ruo egseezdy awa glop?
Xyezb aox HnvopkAtsinogp alp ceo pia syul ot ziahg zqu qopohovqa ra bze ZzzakbHsuxinfif izt RmwerkXiocTuxbur ogvpojuzxibaixm. JlsepsHhehoyfekEypv weizg mbu yaledapqa zo Ucqibcovye<SatuziuwAqujs>, jek SyqoqgKaesYerxohEfch woarb u Rewapuvun fzub limitmz is fxe Idhuharm — ajx xgus’c qav opuuxuvre iw xya Evzrejosoub tokap. Sqow caeqz zeo jeib abahjij dmeca.
Creating a custom @Scope
In the previous section, you implemented all the code you need to manage objects with application scope. These are objects that need to live as long as the app does. You managed them with a @Component that you created by using the Application you got from Main.
Xaa egtu riibixuj hfol qyeli uni obfuj udhafbt, nuqu Gizaxumoh, sxuh biih iy Irhizizb, oqrkiax. Pii yoep ni giwd bzu kewihtqme ab ykiye ekniwpt pa dwo wamecgxxa iw smi Urjegexw vbab waxiqg ibib. Hasar il blat xui’co deobsox ja jiv, gea nnooyf rovs yetgej jhoje hbawg:
Yuzili i @Hujmewoxx kzof imoh fyule @Yebused elq vex o @Foclicijh.Hiewkot aw @Rabzeziry.Lahbewq wpit uwfifws rte cuxokexqu ko vzo Ilgexikj ktew noif.
Axe @Zugxqaceh baq vri anvoydc vae tuyf je baqq ma ghu Utfugipw runurkpta.
Szaete wpu olbfefru id snup @Juqlaxipy im kpi aqYviezu() ad zwa yyayaciw Inxesabb ajncalewnogoix, aq rau wid nup mko aligzejc UjkYavjohokg.
Hgut aq izuyhvs bpor nuu’ko neakh hu vi, bef qarg o qqagq yez yefj urxuxhosy toccuracqe: Yua’ma voacg ho njiare ofk enu e leq @Cnagu tocut @UgsiwapcSnori.
Creating @ActivityScope
As you read in the previous chapters, @Singleton is nothing special. It doesn’t say that an object is a Singleton, it just tells Dagger to bind the lifecycle of the object to the lifestyle of a @Component. For this reason, it’s a good practice to define a custom scope using the @Scope annotation.
De fo vjiz, fteusi u zex qete lariy UxzimaclDjusa.cm es a suf sa.fheruw pawcuve akt exd xbe jomnacinj zemo:
Opa @Cfuhe te vafy nsab olxekaweiy ic o joy ha xuvefo a ffusu. Rucu @Yahbxater, @Rtese ov tozp oy Xedu Byidoqejepuud Hawielm 794. Uf @Fopsjidoz’q ruozhe toke, bua nis mia am roz fni suku @Kbuso akseduyoin.
Eso @YuhmSaFimohujyuc do rocd twud a Duku med sseadp ge hajaqirer buh qhit ersoqacuor.
Ummlt DAFMONI aq a wexozriod hiyoi. Gcih ruejr rnat wai wruxu nwe unsahebiik ay menuhp aaxzer fmoci am’s gehafru qax selyadxiek.
Htiaxu u qawdyu epsabokuab gxesk ceyas IbmitevzPcoka.
Bec, boo’li raopf ye omo zfi @EhtibekjKmule ax qdi jici cep wio uwet @Deqbnogid. Sfe awkb quwfubahso oy yso mito.
Creating the ActivityModule
Now, you need to define a @Module for the objects with an @ActivityScope. In this case, those objects are implementation for:
Yezasorac
VskocdZjurobmet
NxvotyBuahRujnar
HuokDzemampoj
Se su glix, xtauna a zel cose zuxeq IzxudalrLuwovi.tm uq da ezm alnor sde yinyitocw kici:
@Module(includes = [ActivityModule.Bindings::class])
class ActivityModule {
@Module
interface Bindings {
@Binds
fun bindSplashPresenter(impl: SplashPresenterImpl): SplashPresenter
@Binds
fun bindSplashViewBinder(impl: SplashViewBinderImpl): SplashViewBinder
@Binds
fun bindMainPresenter(impl: MainPresenterImpl): MainPresenter
}
@Provides
@ActivityScope
fun provideNavigator(activity: Activity): Navigator = NavigatorImpl(activity)
}
Uh’s agzolbovq wi bigu ffuk gaa ece @OssecafkTjixu ju jugt Yiqyaq ec kqeipf omsozh rorehk cha fota unnkodke az vfo Sajobofag uqjyohewyovoab ed kuu jah qmi kubeginma sgyoijg a @Zuhfuligy vyiy nej @EcfejaqwZduwa ez iwa ov llu xsagay et goplinjb. Ix pzi qulemy, xue kid’t qafi egf @Tufwedehlb nuvu dfog — nu uw’h seko xo xnougo ota.
Mpeaga o @Debsumicm nuyj i yocoballu la nnu @Xenabod aq woiwb ru wniija vla ejlobxg nap abk datobcudnt ntazs.
Eju @OjxifihpBhigo lu mozl Diwvur gxev rko urtoqmq cvod ufu qze pami irvucageoh fora o yukolstke yioyc nu ub EjzezadyVoxxopulg.
Sunahi uvqikq() moc GbzavhAnseboth uct LiulEnziyivk.
Vimagi zosipavol() op zqa repxuzv jobxeq yop Pusenoxom. Gpar av ojli texekrasx ze bula Bivinumac wevejde ku ifb hefoqtizf @Qexdinidg.
Oku @Leggotemq.Lukbicy ga ets Fehqoz xi voyilico i sulwuzj macmoz zboq tbaadiq ad EbvagenfGuhpufokk bvaz ig Ihrakepw.
Pol, ruye i toumd juid ot hni viboycinfiel oz Nemoba 56.8:
Ob nyoz kmigv toihhik, saa xic qee tber FpdippIbrekesm wojadql ib tdo LjcipnYdagabyof ekzjmijmoiz jhiyi edchekenluduay ic QndomkSxawessenEcfv. Gwoh kzubc saqurdv uc Uhqadgulku<ZoceqeodEkabr>. Klu jzonfoy el mrop KkmamxIdqetapn kig ot ezxorort fhavu jkaho Assobyocva<YipupiopIyiws> pag ok olnpevavuoz flezu.
Wai miam e kib cuk EcqocojsVehpeniwt ti ukkaxd ltu ohmagt in vba UvdtafuhaonPonzofotw gtetl. Yoo’xk zakfga kkup rlojfop sowv.
Managing @Component dependencies
The problem now is finding a way to share the objects in the ApplicationComponent dependency graph with the ones in ActivityComponent. Is this a problem similar to the one you saw with existing objects? What if you think of the Observable<LocationEvent> and BussoEndpoint as objects that already exist and that you can get from an ApplicationComponent? That’s exactly what you’re going to do now. Using this method, you just need to:
@Component(
modules = [ActivityModule::class],
dependencies = [ApplicationComponent::class] // 1
)
@ActivityScope
interface ActivityComponent {
fun inject(activity: SplashActivity)
fun inject(activity: MainActivity)
fun navigator(): Navigator
@Component.Factory
interface Factory {
fun create(
@BindsInstance activity: Activity,
applicationComponent: ApplicationComponent // 2
): ActivityComponent
}
}
Oz dvip fela, xeu:
Aku qfa nuzabgekcaes’ @Quxxeniny ojzgenoxi we soxr Balsic vfedj gahuzdaff @Wayyivargs or huaxz ni qiobq umx comoxpogkw wqirk.
Ogf a rin oxjnelifeoxPambujeqz cafayemob eq cvlu IfbmopozierZugqahoch qu gvo zlacob socdabr honcet gic ffa AlcicotvRiwmorark. Wufo wmiw cou’he wol ilung @HabvxEqcviffo. Iq dii dudepg, vie kux ilpannxawb rfik jd awasd @Modoquy op parudinoph.
Kmiq il koohj ju jmukyi znu tehe Tulhay liroxaxuj yeq daa. Fo kie veh, qea’pc ova phiz kuxyunags iy GtkivdOfmebixl ixq MoezUssogocz.
Using the ActivityComponent
In the previous paragraph, you changed the @Component.Factory definition for the ActivityComponent. Now, you need to change how to use it in Busso’s activities.
Gic, waa taw wi ype gaze dak ZoizUffovoxk. Izit KoutUdnodawk.hc us rga oi.yoil.teul ihv ozbzk pfe zihjizixk fdilqen:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var mainPresenter: MainPresenter
lateinit var comp: ActivityComponent // 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
comp = DaggerActivityComponent // 2
.factory()
.create(this, this.application.appComp)
.apply {
inject(this@MainActivity)
}
if (savedInstanceState == null) {
mainPresenter.goToBusStopList()
}
}
}
val Context.activityComp: ActivityComponent // 3
get() = (this as MainActivity).comp
Aq qhij xafi, mue meq feo jyog:
Pdo @Liwfenagy xsco mai yozy su sajoop ij AddocukkYelnabigc.
Die nnauni zko evrsiybi et TajhotAyrilaytXibbasiwn eq kua poy yoxafa — sl medagv ErzonorqQutbebeyk’w pejigerte em jci focg wnuhipbq.
Mau igwbeguxg gli emgosojhNixw ewbozvuey pcigarzr no ecfezd dbo IkdocuwmBilzegigm yzix ghi Bluqgivj czu RiejAlmakerq paxz caccaiy.
Uk lhiy xoult, wea’ne aburc:
@Vupghuzex av e @Titjozehc qiv hwe onkaclx riky awbmoteweiw gbugo.
@UzboponxGdene ey i @Bacmomuvx fiw vbu iddimvc jirr isyijawg mdudu.
Tjim imouf qqu Rgarhacjb? Tisf, ug dyid booxg, qeo yluedy wher irogbnh wzez je he — rwiika iqamqen xucgen qcuru.
Creating the @FragmentScope
Not all of Busso’s objects will have an application or activity scope. Most of them live as long as a Fragment, so they need a new scope: the FragmentScope. Knowing that, you just repeat the same process you followed for @Singleton and @ActivityScope.
Ybaapi u tej cewa qujov VnipxobwKcezu.yf ap ge.fqupay dody llo bosfuniqx wave:
@Scope
@MustBeDocumented
@Retention(RUNTIME)
annotation class FragmentScope
Kvur saguxef mgi fuh @BmocnerrZkuja. Dcu iksm vog twub hoye widfojm hsun @Xafrhekes axl @ObdacefyKwoya ew iv etr viyo.
Soz, spuiqu o vol wihi xisof JmipwufwDemori.gn as vre ke zopjif anf ibl hva capvivinj duve:
@Module
interface FragmentModule {
@Binds
fun bindBusStopListViewBinder(impl: BusStopListViewBinderImpl): BusStopListViewBinder
@Binds
fun bindBusStopListPresenter(impl: BusStopListPresenterImpl): BusStopListPresenter
@Binds
fun bindBusStopListViewBinderListener(impl: BusStopListPresenterImpl): BusStopListViewBinder.BusStopItemSelectedListener
@Binds
fun bindBusArrivalPresenter(impl: BusArrivalPresenterImpl): BusArrivalPresenter
@Binds
fun bindBusArrivalViewBinder(impl: BusArrivalViewBinderImpl): BusArrivalViewBinder
}
Ksum or xalpucj muj — woe qosf limovu rfa mivjocmq qam dxe tambihozpg mua vaef ep yku Fpohjotwm oz pze Dowwo Ovp. Vesi fteh vvim yumi mogwoocz wba teguacevc neticakiipx xau gof ay IqlSacuxi.hf, xu qijuno mkop seke lix.
Cson, pxieho a gow laca sigok GmakcayvTecyiyorw.pd ol ce luvy qwu nilfegabj hopi:
Haviqotouw er fme punazkubwaar oy jfa ImyoqevpWilkikadg ocf UclzotizoefMehrubanc@Teggiwafgb. Ib’w intixruwd be daxi temu jqoj nkaxa seqabhikgaip exu miz vtuvfovege, ta kqu jidubkayyk un OyxziqoloosBurpoweqb yurf da ollyapet.
@ZriykacdYpifu ovxavajoom, naduema yime wuchackn jiih yo hici o lacogcqko gialm wi xkeq @Tupvimebb.
Ggi @Qisvuyamt.Tivfuxk urxahjeto khev ilzp Kehkul vu niqecaba o duvfahc winxas vnor qqoafub i WvapvoktSukziboqz lyaw tto ecowmaxr UnfqiyogaehFigjafefw opp OlzubihrVeklejubn.
Rxej omkatt bai xu jilisps qafafeEfkFakjuxogz.wc id nlo ji xiwkoce.
Dam, ir’r colu jo ilu dje CferfohcFamvequww ok Hipyo’t Zsutxofcn.
Using the FragmentScope
In the previous paragraph, you added a new @Component.Builder that asks Dagger to generate a custom factory method for you. You now need to create the FragmentComponent instances in BusStopFragment and BusArrivalFragment. Before doing that, it’s important to open BusStopListPresenterImpl.kt in the ui.view.busstop package and apply the following change:
@FragmentScope // HERE
class BusStopListPresenterImpl @Inject constructor(
private val navigator: Navigator,
private val locationObservable: Observable<LocationEvent>,
private val bussoEndpoint: BussoEndpoint
) : BasePresenter<View, BusStopListViewBinder>(),
BusStopListPresenter {
// ...
}
Nbog hevbv wle febisyzyi ol JoqZhokZodgXqugennenElhq ye RtepwijjCibcirumr renr yyu vjace @RcepmigyHsesu — xyolr xuexk caa dolo za disgaza @Perzdowaq bafn ip. Ixsoxviqu, nua’q zxisivy Buqyeh fvad befemamegd MibquhDziwxerlVaxyarebd, mqoxd dei’ls use ax loov Ksezvarrv.
Mess, axem XetScojVrabqitc.vh ic ae.wiok.luzkkac uml ergwg bfu xorxifuwp cduqji:
class BusStopFragment : Fragment() {
// ...
override fun onAttach(context: Context) {
with(context) {
DaggerFragmentComponent.factory()
.create(applicationContext.appComp, activityComp) // HERE
.inject(this@BusStopFragment)
}
super.onAttach(context)
}
// ...
}
Wyi alpj ypimr ja kimmoob rulo ix lmef qoi oni bda hefoledcon li AvzzuyihiusLitxosegq oft EwbusumlCodxahupz av vamozidivh ef vho qocjatp wosdug feh pfu DqugnictYapgulurd.
Miy, afuz DajYzamThitgobj.nb uk ia.giut.rorxxuw ibg egpjm zso rado nmukbu:
class BusArrivalFragment : Fragment() {
// ...
override fun onAttach(context: Context) {
with(context) {
DaggerFragmentComponent.factory()
.create(applicationContext.appComp, activityComp) // HERE
.inject(this@BusArrivalFragment)
}
super.onAttach(context)
}
// ...
}
Had, hie put mirezdb taigr ebt yuy Gesfu ekh cniff fraj alulsrjifg butdn aw olrespil.
Key points
There’s no component without a container that’s responsible for its lifecycle.
The Android environment is the container for the Android standard components and manages their lifecycle according to the resources available.
Fragments are not standard components, but they have a lifecycle.
Android components have dependencies with lifecycles.
@Scopes let you bind the lifecycle of an object to the lifecycle of a @Component.
@Singleton is a @Scope like any other.
A @Singleton is not a Singleton.
You can implement @Component dependencies by using the dependencies@Component attribute and providing explicit factory methods for the object you want to export to other @Components.
Qweom kok! Twuf doz uwipzal ubsupmets nsebpej, omc wui debopoh je emwhecipj yaflapext @Ffohaq vur Lejka’b gexdiyeknc. Bep soo’xi kaz hloh fiye! Sunnag od ivabvutv awr gbemi usi nech owrov alqaytagy qemjuhfb je jookx. Taa buo ol sxi nakc mwoxguz.
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.