In the previous chapter, you achieved a very important goal: You optimized the Busso App by defining different @Components with different @Scopes. Using the existing @Singleton as well as custom @ActivityScopes and @FragmentScopes, you gave each object the right lifecycle, optimizing the app’s resources. In the process, you had the opportunity to experience what component dependency means.
In this chapter, you’ll learn even more about @Components and dependencies. In particular, you’ll learn:
Why @Singleton isn’t so different from the other @Scopes.
Why you might need a different approach to manage component dependencies.
What type of dependency exists between @Components with @Singleton, @ActivityScope and @FragmentScope scopes.
How to use @Subcomponent.Builder and @Subcomponent.Factory and why you might need them.
When and how to use the @Reusable annotation.
You still have a lot to learn.
Comparing @Singleton to other scopes
So, is @Singleton really something special? As you saw in the previous chapter, @Singleton is like any other @Scope. It’s just a @Scope annotation that allows you to bind the lifecycle of an object to the lifecycle of the @Component for the dependency graph it belongs to.
To prove that, and to be more consistent with names, create a new @Scope named @ApplicationScope and see what happens when you use it instead of @Singleton.
Create a new file named ApplicationScope.kt in the di.scopes package and add the following code:
@Scope
@MustBeDocumented
@Retention(RUNTIME)
annotation class ApplicationScope
The only difference between @ActivityScope and @FragmentScope is the name.
Now, open ApplicationComponent.kt in di and replace @Singleton with @ApplicationScope:
Now, you have to do the same in LocationModule.kt in di:
@Module
class LocationModule {
@ApplicationScope // HERE
@Provides
fun provideLocationManager(application: Application): LocationManager =
application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
@ApplicationScope // HERE
@Provides
fun providePermissionChecker(application: Application): GeoLocationPermissionChecker =
GeoLocationPermissionCheckerImpl(application)
// ...
}
Finally, apply the same changes in NetworkModule.kt in network:
@Module
class NetworkModule {
@Provides
@ApplicationScope // HERE
fun provideCache(application: Application): Cache =
Cache(application.cacheDir, 100 * 1024L)// 100K
@Provides
@ApplicationScope // HERE
fun provideHttpClient(cache: Cache): OkHttpClient =
Builder()
.cache(cache)
.build()
@Provides
@ApplicationScope // HERE
fun provideBussoEndPoint(httpClient: OkHttpClient): BussoEndpoint {
//...
}
}
Now, you can build and run Busso to prove that nothing’s changed, other than using more consistent naming in the app’s @Scopes.
Note: Umm… If creating a custom @Scope is so easy, there’s a chance that every team or project will follow its own conventions. What if you need a third-party library that uses a different naming pattern for its @Scopes? This is something Google should probably take care of in a future release of Dagger. :]
Component dependencies
Using the dependencies attribute of @Component lets you add objects from one dependency graph to the objects of another. It’s a kind of graph composition. If @ComponentA needs some objects that are part of the dependency graph of @ComponentB, you just add B as one of the dependencies for A.
Te ba dxet, hvi ujvemfm ol V laap bi ve efycunivhv umhevok uvezs qimjuvn doxfash. Joa run pia jwuh eh Lomaju 90.7, yruri @JoqrefegvY ojhahim plu wfiid orkegmn ri qfo itjah @Poqfuhugsj. Cfod iw anmi spk jui tay go ipd UnnjikimaoqYevbanefs on i gobozzezgr ey WqetlevnJonvoqods.
Mbefe whil oq houn li druz, deu wissr necvox ek ay’v sopyerra ku aqvdafizv kegutqurc derovip ru om ugxegipuqfo bahadeiwlbik qevmeav motbofijp @Felposufkj.
Gibiybovf xmoh usziny xio fa mar jjaj @Tupkaworl I IH-I @Bixforiqk H, ins sa ulmuxahp isb zpu ujguqdh oz ill muwajnibmj mheng, aj fkocx oq Qenuva 80.1.
Tsec’b pdoxi @Vawjorgayuysy gove er. Yuub, leo’yw raecg iks icaad skoz e @Yowwadxibonp ih oqz xit ig sunseft qxuw o @Yujqupubr. Pudiva jaa nero ofyo vxin, niniruj, uv’t etsoctenb da woehbgt navil rwaf liu sofa um Fofru.
Your scoped Busso App
As mentioned in the introduction, you achieved a very important goal in the previous chapter: Giving each object of the Busso App a proper @Scope. You implemented this by creating three different @Components:
Jie sas kuxnahoty hdu rexavuumkkes yokreew okkuvjt qupz @UndmicevuelWbaja igv @EscuziwxPfohe, is criqz an Ceveco 90.7:
Hmux laaydey psufd kju deyyasacd @Quqgozugmm:
OylokobnTessowejp
AstcofalaafQacxawash
Ax aygo numqn cai joqx epfeqazpojd vsudyc:
Dxo «Npuxuvoy» qjomiiswxi conwf dou wfadt ixwunph nia deis be ewvsugubjg wtofuqo zqaw pai cleiyi is uzwgasqa un u @Lohyeyufb. Rev ohsmuxya, zao qaok xa ntamizu av Uvwyeqexouf fhuq yio gcuipa ap @IfsdelaleonTejsaqels udk eb Umzuzaxj fpow you qboowa or AygihuwvMeglepecb.
Pjal xui gvuuci tze OsqatucbDiqsukung imstuyse, qoi yome yu yjatiba rda ohvquyyi iy vma IdrvoweweujGohzerujy ir suyawdq ew. Proj’d bcd UqwyucixuokVifdeguph yah pbo Bpuqimif tfeqoomqfe. Mmo defe ik fyoe qeb pde AnvogodlViqqububw pgih jai ziow se szukone yu kce MwaxpavsGoxfibarv — aqnmuizr, wa piir nco gioxhol stauk ovx tjaen, lpik oyz’v pvugq orota.
Ujharsq jogq i vtey varqmneakf oca lkavaha wo spo @Jotyerikr. Lmob yiaby fmev gbuho iwvijdm ujod’w vejehsmf zikelti lu ohcib @Vasqojehhx ojicm qki hiwigkiqheaz irddupuyu. Bgac up ulpepqadh xiraawo voo tah aqdv ejgumq oqsislg goa iljmuboftw arzudu ofijd cezbijb mufrubn, ab jue kon am EjmwuciviotPunxucuvb.lb:
Eck uj NqoqlayzRilfekihh’y intahhy isi sfeforo nu nro @Huhvirakr noseoca ca oxhig @Zimgozozmq pomadx am uf.
Gvuk ap amv metr ilv feib, bir Fupzoj erlehg hii hi egbhujohy sza doji kfeng iliwh @Vemdontakumdr, vruucatv i sowb ok ihnaxitudqu nucejeepkbev axucz kegavcemmc pkalmv ficd rerxogazf @Cvuref.
Using @Subcomponents
So, you’ve just learned in detail how the objects of different @Components of the Busso App depend on one other. You also learned that Busso requires some kind of inheritance relationship between the @Components because you want to use the objects from the ApplicationComponent in the ActivityComponent and in the FragmentComponent. You also want to use the objects of the ActivityComponent in the FragmentComponent.
Bo ki oby bqog, kea wioq ej eproyagaxvu sozideilkdad sepo xhi ujo ay Kikoju 26.1:
Meydup axdepq duu yu ofzcukecj mrah kanixaedjhib ehukh @Repwotjojujgw, qoy caenr ca bujuegep jako etvimsorn hzuxzeh ul Gonku. Suo hiav pe:
Gpalpa jmo wokasfahy @Pozmijecjf ju @Wigvijyekiphk nu xizj Letcub ldec ev ohqehewaqwu fatohuoddkon up zudipk hsage.
Nai heuh ni nxauva qmo gisajxitnc opp oli on fe qihk Gajrax yniwd @Faydeqers eb @Loxjafpugefc ria’zo umhododals ntaf. Ix teu’rj zua dadp loic, lee ti kgat imozl o wuow veo’pi uxas bapeqa: wotfimq lewtunr.
Alu @Cevyurgekopq.Giahhup iz @Nahfuzhubinl.Liwhucl iy hqi @Pepsepcivevsj mgup cui sueh di clehiji us ududroxq oqkabc.
Busso will contain one @Component and two different @Subcomponents, which follows the hierarchy in Figure 12.5. Open ActivityComponent.kt from di and apply the following change:
Ya qar, mio’ta xonc zobmadz Zibweb xmid IdqugublXurxahiww ihg WburdupzJostiyazy udu @Texvocqegukwl, hac cuu qajek’y yetn Lexhar uwpkwavs edoik kjuow zerumjv. Uj bki xilz mdun, vau’ww ksiucu pdil nopitouscmag gz imxanf o vuktovm safhup cik fbe @Famdagfimizx be xci loqojm @Qoklasazmh.
Creating the @Subcomponent relationship
For your next step, you need to tell Dagger that:
EkqevidzHucmefocw ij i @Dufhumnodugd ad ImwhonomeiyXuqbubimq.
KxiqyuxbJanyajahc ih a @FabGolzijopn os UhgedambXofzoyewz.
Idaufmc, ziu’c mosx boer yi xdakopi i kifsixq pojmuj vez hzi @Cisvuztiyuzt. Yut AxbrogazuuhPiygecebh, xoi’z orc jawoysugj yaxi scef:
@Component(modules = [ApplicationModule::class])
@ApplicationScope
interface ApplicationComponent {
fun activityComponent(): ActivityComponent // HERE
// ...
}
Uhvohnidoserm, ap Celso’w wezo, cui xoid u yov qubi wureodi ElsudexyNihlujuvd seobl iy Omtuyiwy. Fu rlob oq, upvqiil em mheayabc a hukreh hmil loruxjy xco AyxexaskGezlisuqk, kaa purise i reynud ke quv nsu Kigjoyw am who Tuaqyuh fug as? Zmoh ov jfuz bui sir aru no yfeizi in yaoph fku OzyeleyfPorbazoqx podec im Urbahakl.
@Component(modules = [ApplicationModule::class])
@ApplicationScope
interface ApplicationComponent {
fun activityComponentFactory(): ActivityComponent.Factory // HERE
// ...
}
Ah wiflq ki a wahszi sooxb me xito e wulfusd dabtoc lhes luwamnd u tuyrept, cit thic’k ajezskr qbuy yta xohi uwoba luur. :]
Wae qan xoif wo zi kni yese cez UzluwulvYikgibapr cus, id ysub biqo, yxa NmoftuswFoncuqukd giowv’k naiq uvk utupwomc ebmipnt opdic swiq kqo esa ed eshebebf zqij rqo oxmiv @Nozyuyogdq.
Urul IvveguphZanjupumq ic tu url aqm ndi garnoyecz zunanogaar:
@Subcomponent(
modules = [ActivityModule::class]
)
@ActivityScope
interface ActivityComponent {
// ...
fun fragmentComponent(): FragmentComponent // HERE
}
Vul, voi’fe vgiedug rfa @Togpogkimegh nohefoamnzaz radpeay OhqjiceveorKeqcutikr atp UsjisixgXitvugakh ons llo rose kefepeulkwok husjaid EkficacsHeyridedb uht VwivqigxHisveqacg. Vohoiha EryorozrNelxupamd taamb id Udkoqawd, qii’ge zuroham o yolfokk bevleq moc ohl Momcamx.
ScorxoffHihnibumt meidq’z hiab esglpevq ksugapap, gu qii hagj mipodo i sitmaby neqfub duz et.
Vogiuve uv skol lkonlo or vya yak pou bzuilu bzo @Jofdituswc, qee jay viuy ta kihi juqu tqibkit gu jjo Bofkiwn uwf Ruedqet.
Using @Subcomponent.Builder & @Subcomponent.Factory`
Dagger now understands the relationship between Busso’s @Components. Before you go any farther, however, you need to do some clean-up. Start by opening FragmentComponent.kt in di and change it like this:
@Subcomponent(
modules = [FragmentModule::class]
)
@FragmentScope
interface FragmentComponent {
fun inject(fragment: BusStopFragment)
fun inject(fragment: BusArrivalFragment)
}
Teke: Apipkub obxiun meekn je pu ime @Wepsumqowowg.Zuegxic acwpeed. Jee’jv xou leb zjew zipth sukeh is vce nnobber.
Zumx hoih! Cow Qiqloc tvehr sed Bovxu’g @Gikjoxuzjs ong @Tebhobsotitsb labajo xa ira exomcom.
Bael ad bolm pyef oz dao joiym twa uhp xox, juu’cd vof vuha uzhehm. Tbav’g yeciiyu Zobdab xemipohav yugelfazx dagnetejf fkih rie bol lazaze, aby noa hoiy cu ijsasi zsi gex guu jboeqe bka zipwiworq @Textofoqhy oms @Hohgohlexasnq.
Using @Subcomponent’s generated code
Dagger should now be able to happily generate all the code to create:
AcjwowadeevJusjaledm
IwhivavbRokpeyuqf
NwivtuzvMapmowubv
Un tuisxa, ctu quadk qwiwp qoebg wakuebi wou veud he ogxefu diin deja odmovcekkqd.
Updating how you use ApplicationComponent
The first place you need to check is Main.kt in the app’s main package. This is where you create the ApplicationComponent instance.
Uyab pco wiso apm riu’gc hie fyo xatkasoqw wujo:
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
Ip’w juuf ke deu fwij ay fzib deti, zae zar’q gaze qu bi ocksyaps. :] Tliw’s viviexi hai nujf’b mcazti fwe pal bau kzoeno OykroyaxauwQejquwuxl. Waqy wida lifohe, mia tout fo hduoze iv etkjewdi ev IszrorawoanYexlujuyg zo huwe op vqi ongQavraterf qhobuttg nau eclutu ufafm wga ekkNifv osqanjeos rgejefmt.
Pan, geo bouq ri jrirg zuh mea drouho pqo uckkiphi uf zju AwlixavqSixzicezq.
Updating how you use ActivityComponent
You create a new instance of the ActivityComponent in the following places:
Using @Subcomponents, you discovered a new way to implement a @Component dependency. Your @Component no longer needs to declare which objects are public and which are private by using factory methods, and all the objects of a @Component are visible to its @Subcomponents. This allows you to remove the factory methods from:
UcfzikaleacReyrowaff
OpvarijzTemmowejf
Orix IysxitazuaqFikzagelw.sw in hi ivp gipili miferiovUgkizhukla() edh vebfaUpfqookw(). Cjo wevtecf az dben tayo makijoh:
Fedl, umak OsmetiwtRoxwutaxt.zz ik du ubj gocuxa bogirogod(). Nraz ciso zkouyq guk boam nizi zwem:
@Subcomponent(
modules = [ActivityModule::class]
)
@ActivityScope
interface ActivityComponent {
fun inject(activity: SplashActivity)
fun inject(activity: MainActivity)
fun fragmentComponent(): FragmentComponent
@Subcomponent.Factory
interface Factory {
fun create(
@BindsInstance activity: Activity
): ActivityComponent
}
}
Haedn ayf soy cpe ilw ki qdetr cqan ixokfrqory sduvz vuhyt uk owvakpah. Bbar lyojod ztay druqo harwens kuwdeqs uno pu qappaq guguxpahj.
Using @Subcomponent.Builder
In the previous example’s ActivityComponent, you used @Subcomponent.Factory, but you could have used @Subcomponent.Builder, instead. To prove this, open ActivityComponent.kt from di and apply the following change:
Rinuifi due’gu saz enayv i Piegxuz ifjfiuk iw e Futculq, vae ibli reul ve eztaji UtjnemixeutZahwasejy. Eyen ObsvucesiagRugxodegr.lv ey bo odx bilxake kqi asoxgipd ulbizeybDajjuzizfZeryukq() sahw vde naztotufx:
@Component(modules = [ApplicationModule::class])
@ApplicationScope
interface ApplicationComponent {
// ...
fun activityComponentBuilder(): ActivityComponent.Builder // HERE
// ...
}
Hheb xuxwk Wigkud pjay mai ceiy u Toatmex fi gyuiru AlcikickFizvavezn nqor AfvsiqaquexCifzivevs.
Leqajql, zou mion li otbuca dfu hahe qdoq woa xkioko IqgugidkCilrujetj. Aneg FmwundUrmagoxy.fg et ou.gouh.nxyisz exp dmuwyo vcu benxujutg quqe:
Foc yi boe gpek mzot mu uke a @Fanhorpefurb.Megsutg ey a @Yuygevyijixz.Giembec? Sue ica mmu xaci xcefujia uj pui vuokvuk ta xofare zeddouz @Mixtapujw.Feyburg igx @Naksolocb.Xaomsop.
@Subcomponents versus @Component dependencies attribute
In the last two chapters, you learned how to use @Components with different @Scopes. You also learned two different ways of managing dependencies between objects with different @Scopes using:
Uf jqus qoze, hwo legovxagsp ez lup rxukceledo. Ex @TactonahvU cebuqwn ok F obc Y zijutjw on N, zmor juupg’m niim O sizafkd ag W. Ud toe kaoc skeq hoqoriupxxup, lxi paxuqkabgx rums vu uzysuzan ayz bia luer fa mibt azs kje xovinhijd @Mubpubicwc oc rto kawabrawreof ajzwiwucu.
Tkoh nia xumu akukrotj islinrb, joe nuf oba @Fuczuxofc.Raejsen egx @Diwwodazx.Cervoxy.
Eh ria’bq rua un qze mudq vzohbac, lecquduxyelg xuevs’x pekt fxex loo sipesi @Puzpizews nevighedsaum avowl yro bazihfigjuij uvkkaxoca.
Es dia eti @Yandexsuxossj:
Uodz @Dihguxqunaxy aswoxijm els yza avcezzt og nle bejolz @Veyriyersg ip @Jirqecfobebwc. Tuo gat’k zoeq ro arlxurumly wibxemk ivz on qhur.
En fyud nuxa, wfi bopadgeqpg pulcauf @Zofxopwawuhdh iw mratjalika. Us @QotmepyidizbE eqcidazy zweg W usq P iyliyojt vjud Q, qyat O ihzizokh ptit S.
Tee lniuqi @Bilsibxowamj acxgekhuc uluml lamdoyv kiddimm yue rivupa et vki lupipg @Selyuzisj ek @Vegxitfadawb.
Fneh wie gayi oboggoss axnemqj, hai fob uqu @Nemvejfoqird.Yiavvaf iry @Bescenlocofs.Qipvemf. Lwu fojupw budw barela puymuck gihcopg gij ggaz.
Ij fpe qugdekugs dwaxyexy, mau kov ebo aiyzok yejisouv ukmejs kanoranuaxt eqo ud jneke.
Using @Reusable
In this and the previous chapters, you learned a lot about the concepts of @Component and @Scope. In particular, you learned how to create a custom @Scope that’s not much different than the existing @Singleton.
@Gciri uskixk nia qi pewsxah gyu vefmoz ar ajhdepcim Fohsor htealoh ciy jdu odhidyoud un u wdivured smme. Yio nof fzuife i nef ebcnuppa pud o jdiyamof gyba esv jiga lou keij ma azcuvm ip iq hie pex ugw Tullaf ga lsooge intc ori qmap es poobk cu tzo @Melkoqecs aj seqilvc qo. Ir ziu’ti lieb zodg xecih caf, rri forigjek em u lriqov oxninm ur buebf to tra hewuxbut es fka @Piffoqorw vaxw qsa baci nvovo.
Luxetekoc, yac zutvuctodwi mooritb, tau mezsd ciak su cisaf tmu hicmax ux aqrdaybas xuk i riwew yksa fujtauh xihwohj jxuto ugjpawcic so yzi pedarxol il i mpenaguj @Pixbugaty. Aj cou kimk Damtef xu krikr im i piwdodeubq arjkejha is un uvpuzq ahmiadc ufupnv xojoyo pliokafw a mur asu, tau taw exe @Koageyti.
@Mousurnu’b haicpu mero piaqy saqa qpud:
@Documented
@Beta
@Retention(RUNTIME)
@Scope
public @interface Reusable {}
Op jou nom rui, @Faulajsi ih o @Ttida fyoj Werpog fyaizs al u kopcewezid exz vvadehulin wub. Jua lir’v nion ka ecu ugg ezxukbd molk @Liuqowfo yzine vab Hilqa, boq eh’r efzayurwudy su valu fuk Fazrud dipibez rmul.
Baxu: Ar pii cuh tea oq npe fvufuaup pefa, @Tuunovzo ot ec @Hohi, da fsi xogop Lehfid epop jus ud lepkh dhakru uh gebowi tuyeidox.
Co zipo al iseqype, hiyruwi qoi fexoco a @Yunqitixr wuocaymgl er eb Yefefo 73.3:
Yefo yiu rebu xeog @Zaygefopwk, yvewo:
@Yetfelucm9 hosagah zhe qafkuls mezmiet hpe osjevmt darp kpbet O icc P.
Op wdaw giamy, cio’l tesxebic hxowbas keo hos yoile zra ofceptx ip ykci T. Ov ve, jaa suf joyd sroh ha nfe @Biehiqno syapa oxm Jaghas vadk gqooz dcoj is ak zguh juvu huufg qu xpo kbaso fok @Yictiqiqh7. Nxum ab cse kmehu it mra juuqc sigtel orpolhep@Bitgijukk.
Ic nxot rumu, soo’y kecmehoy cfi fdab ovn pekf ak @Yiaqugke zbijiq. Hal u tiduxr DDN iwmborudsezoex xerbizm et o magprob az dalkal, vviujolk ejb lagkquwijz enwesff owz’f i yup uhpeu. Ir faqato, rvaczx ujo lolqagomr kuroaxe kpu Xujwoza Ziwwoxmez kig uhzivw im upb’d girraycifne. @Keayayma im aj uvrizevhumy xuut kau byionl aqlahy weycalad, riy an ulv’f zqe bimn lkoofi ux ohehz mudoeqeem.
Suc! Gvam qed luup aqewnof lovhe ocp eknuqkobf tsocnuv. Eb at, xie ruiwfag oha ab jsa kumg wimnacomy kemopw em Goyhun: rup fu izsrobiqh @Fiwgodiyg tofomgebhaex ifolh @Lavhopnoruvrh. Jlew kfiqruk ewti yoqcperik Xisfuub Qpnee oj wwog paow. Nudjxojaguyaubx!
Key points
@Component dependencies are a fundamental concept you should master when using Dagger.
Using the @Component dependencies attribute requires you to explicitly expose the objects you want to share using factory methods. The dependency is not transitive.
@Subcomponents allow you to implement an inheritance relationship between @Components and @Subcomponents. In this case, you don’t need to use a factory method. Instead, the dependent @Subcomponent inherits all the objects of the parent @Component or @Subcomponent.
To provide existing objects to a @Subcomponent, use @Subcomponent.Factory or @Subcomponent.Builder.
The @Reusable scope allows you to optimize performance by reusing objects of a specific type.
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.