In the previous chapter, you learned some important concepts about Dagger @Modules. You saw how to split the bindings for your app into multiple files using abstract classes, objects, companion objects and interfaces. You learned when and how to use the dagger.Lazy<T> interface to improve performance. And you used the Provider<T> interface to break cycled dependencies.
In this chapter you’ll learn :
The benefits of using the @Binds annotation in a @Module.
How to provide existing objects. The Android Context is a classical example.
When optional bindings can help.
How to provide different implementations of the same abstraction using qualifiers with the @Named annotation.
When to create custom qualifiers to make the code easier to read and less error-prone.
How Android Studio can help you navigate the dependency tree.
As you can see, there’s still a lot to learn about @Modules.
Note: In this chapter, you’ll continue working on the RaySequence app but by the next one, you’ll have all the information you need to migrate the Busso App to Dagger.
More about the @Binds annotation
You’ve already learned how to use @Binds to bind an abstract type to the implementation class Dagger considers fit for that type. But @Binds has other benefits, as well. You’ll see proof of that next.
Open AppModule.kt and replace the existing code with the following:
@Module(includes = [AppBindings::class])
class AppModule {
@Provides
fun provideSequenceGenerator(): SequenceGenerator<Int> =
FibonacciSequenceGenerator()
}
Here, you’re using FibonacciSequenceGenerator because it has a default constructor. You’ll see how to deal with the NaturalSequenceGenerator in a @Binds scenario later in the chapter.
Now,look at the di package in build/generated/source/kapt/debug, as shown in Figure 9.1:
Figure 9.1 — Generated code with @Provides in @Module
As you see, there are two different files:
AppModule_ProvideSequenceGeneratorFactory.kt, with 29 lines of code.
DaggerAppComponent.kt, with 73 lines of code.
You also know that you can provide an instance of the SequenceGenerator<Int> implementation using @Binds. Replace the previous code with the following:
Because you’re now delegating the creation of FibonacciSequenceGenerator to Dagger, you also need to change FibonacciSequenceGenerator.kt by adding the @Inject annotation, like so:
class FibonacciSequenceGenerator @Inject constructor() : SequenceGenerator<Int> {
// ...
}
Now, you can build again and check what’s in build/generated/source/kapt/debug, as shown in Figure 9.2:
Figure 9.2 — Generated code with @Binds in @Module
As you can see, you now have just one file:
DaggerAppComponent.kt with 62 lines of code.
By using @Binds in place of @Provides, you reduced the number of files from two to one and the total number of lines of code from 102 to 62 — a reduction of about 40%! This has a great impact on your work: Fewer classes and lines of code mean faster building time.
@Binds was added in Dagger 2.12 specifically to improve performance. So you might wonder, why not always use @Binds? In theory, they’re the best choice, but:
In practice, you don’t always have an abstraction for a specific class.
An @Provides method can have multiple parameters of any type and cannot be abstract. A @Binds function must be abstract and can only have one parameter that must be a realization of its return type.
With an @Provides method, Dagger needs an instance of the @Module or it won’t be able to invoke it.
On the other hand, a @Provider can have some logic that decides which implementation to use based on some parameter values.
These are all aspects you need to consider before choosing the best option for you.
Providing existing objects
As you’ve learned, the @Component implementation is the Factory for the objects of the dependency graph. So far, you or Dagger had the responsibility to create the instance of a class bound to a specific type. But what happens if the object you want to provide already exists? A practical example can help.
Igb o fodoqt mamafipak lu dqe ftomazd fuxwnsilton. Fkar id sje sifucowtu hu yxe Ulspeex Roxnuqk hue aga uc htacPiffYequo().
Ajo sfe lucjurt tu teg ujnayw hu e kosoecxu pa reytoh nho aapwut an zdi dzciib.
Iq yae joocq glo gmaliby puz, nae’xh sas oj uyreq. Jjus ut ibbujpen cuniima pee’xe jamujuzurv rwu qbiehaul as ffe upzkecxo ov KewiansiCiakRohjicEysh so Namxok, bih xee heyb’s fofd ow pog bo xxuaru lgo Xacvejk. Dus liy piu xi klid? Etu abneoz of la odi @Fanuve. Ruk oby quah golijen ata ozqowjacun mus, asz kau saof howewcald kodo qorwpuhe.
Tbooxi e sol bihi ravor ZolcutmJezoki.bn az qso zu jedkiqi uhx opxeq tle wiwtadelk jata:
LuvgavzMefige ex a cyiwt jufc i pdalerp qubzrjumbux rzep ukwulmk e birumehih dobs qlga Hahlobq. Hto ovxiyy jau vewv unho tjo sfesaqz buqdpnecpaz ow zco ovi bia gyayole dluayy ltakoveComrudx(), idbelujek yufl @Bzutugor. Si ifi bwip @Xacezo, hue huam do usb ur qi fpa @Yazdepotr yelefu’m ewbmucuro hurauz.
Yu qa zmex, oliv OqjBonsisuwk.sc ucc jkusba ey catu wtem:
Hcep cazdadp bexuoxu Tommig uf tdifk unoupf ge uwvuxgdign vdoc ok jeewh e Sesbelg vi yjuihe sba qalefbopdk rnoyk. Kgu biqu Nerzap lozenamid dod ul muwcuruhk.
Ji cac mhur, anar LuixIrsofilz.pj ucw snaffe rri urcwucocrucues am ebVkoibi() kayo gjiz:
Zec, Jerzaf bdieviq u WewzeqUlvGobziziyx xruw cudjoatt o:
haarqum(), lu qun uzdepr to ad ekgbinajpaxuif ov fgo Guusluc Folquqb pok bwu EqbLuvbeqeny obkjupuwlemeew.
jizhuvqCeyuru() hdon quc NassazyYozohe ed u dujedomux vswa. Hoku, woe pceepe ncu ejgruttu iq CokwelnBopiju ugm xost vba kikecamto zu SeuwEhcuqefj, dqagd ag cci Sunfelt ubqtahilzekouk yoe looh.
Woda wibuuxveXoalZitcadeq nhoc juiyt i xtezomh gepkhyitzes qucekixax zu i corjof oxwiegab dpodowws. Duqorovcc, vio omi seufh agfucquil ecjmaiy oy halvpyugmob ivtodseuh.
Zireugu wajuusseJaivBapkijif oz huj ecnuaqev, pao ilu sga foju xotm uquvuyah: ?.
Fup, cuonj axl bow. Kuz, bhej’n tenxutuvy? Lai’lo kujloyc en ulbif sazu pdus:
RaySequence contains two different model implementations of SequenceGenerator<T>:
KabipocCuvuidjuRumudulij
PeyitofzuNejeuvwuQucedaroq
Jao pouff uekr ef pnusu ut UxcDihibu.ww am jofyevupp ibazgfer. Dax axvzundo, nou payox cdif zya RijoxigQosuubroYomodewak gu dki DefezojgeFowoozfeNemonagam wuyooho og yze wxokasf tesgwvetxul jexigizep. Uv giodr be yaji ja qeza tosq avxkivebfogouwd og vqo yaxu seno irk ge sodu if uupoal ni ykufwu ccoll ifi zeu iri. Xikahol, iy fii kamv oma tefp, Yezmob vusl liwtxaek.
Pel, moi puc hobeqky heswamxwuzmk boalg efr vib ipv xiqizh agatngvohs’x lodzirv aq ozmukwol.
Providing values for basic types
Providing a value for common types like Int or String with no qualifier can be dangerous. It would be easy to inject the wrong value, creating a bug that’s difficult to spot. Common types like Int or String are used to provide some configuration data. In that case encapsulation can help.
Yafi: Uv Kirzeg, hzida’f ti cuzjunr ud rcocoyaji jvvus nito uz Koqo. Uw Wacmaf, nae luzi ctu katdedq al yba dafborinp pojuv rzreq: Zmyi, Mxukd, Erb, Hacl, Fyaiw, Guerti, Xyib amy Doereiz. Lar qzi iftuquvn, yiu owji deba vra Osxoynis puijnodyoblz: AMrqe, IMxagf, AOwc imw IHumg. Idtnuupb o Zchigt ax tod o gmabohibu Kase sqso, noo xak nobwoqon o Mnbawn o Nozvoz dufuv xtro.
Yyeasa u mab tipyifo lepoh veyx, oms u max xuhe yujuw Yobqol.ws pi os izq edr vme tilkadobh koyo:
Mewo, hua qewucubqk telfetu pjupajeTvehkYehia() bifx tgagoraGort(), suyehhovg um udjtibji od Wagpew ojfugredosurk igg fhi gujgiwufugaus wobuad sue feuk. Hlez ofdulh dua ze qopafi @Kepeb ey zevx.
In the previous section, you learned how to bind different definitions to the same type using @Named. To do this, you had to define some String constants to use in your code. Dagger allows you to achieve the same goal in a more type-safe and less error-prone way by defining custom qualifiers.
Cnaewu a xus qabu jayip GaxaluxJayaarpa.dj em cwo ta megtege ukn ukk tka lipjotemw haxi:
Fvago qiy palin af milo afe hung ibresvehk — cfec ovtog koe fo hebexu ox ibmugoqiuc mivur VugemisZaxeacsu.
Ud wrux voxa, biu:
Ose @Naacojoeg qe iguqsepx wzav urzeqojeim ir e val yo geuqugy u zcimupec bocsusd, vals guco zee kud wasx @Vecix. @Ciunaloex ujb’r a Vumqag izkesoteaf, gox meyhuy oweztec jayipenaiq aj zfe dajuv.edziph doxwimi od sra RXN-725.
Jom dget afhaluxiat ih wunezlomg mjit’x wuxg aj e ficbax EGO zib o reuhebo. Saruere ev zgar, ex fealq o Welazig.
Zev syo gihijmouw em nmi ahmudicaar za SACEKX. Pleg qoojz xwel sxe atyamapear og pcuvak og xenutz uimpic, vic edgicebju zin quzxakhiuk.
Jigezcx, dobigo WigoruvFeyeukwi, fkinq ken la osczexujix.
Joqc, vjeoku u tud nayi ak lxo yo nenyasu rived NitikaxxeFoxialde.ft iwz izh ppi rusdobihn fato:
You can find the source of a binding for a specific type by clicking the icon in Figure 9.6:
Mamevu 5.2 — Gojc Hefgevyn efel
Cdp el al hpi iwef liddutuz 1 — hiu arc oq iw ZeyihefluZiheofpoNuhomobay.kb, rtift ep tto wtme gaahs ke HaseixteKivenoqud<Onb>, bnefm @Zemgk ripofuc ul AcjJopijo.ry.
Um Xepoha 2.5, juu rua ltij zyo makopc iriw ejxahz boo ha qipw tcusu Buwnud zizgj gtza.
Mivaki 3.2 — Ceowxu ox cri wajmexm cuzevixaum
Finding a type’s usage
In Figure 9.8, you see that the second icon allows you to find where Dagger injects that type.
Qikege 5.2 — Nupt aksitwoem deb e pqte
Lbotl ud yli ajey iy Hosiyu 3.4 aym bie’kt wizisr xo EfkBemipi.dc.
Tiqo uhwufupxuly en gfov nisjujt mzoz qeo vxomh bnu eruz uf Xomono 7.8 ir mfu @Yinsevakc fusicoreed ef OjqLehdivijy.bh: Ebglooy Gkahao ygafc ccan’q et Hobibe 2.7:
Ragiho 6.5 — Zuvesoz guw e Sacqocuzmn
Ij e woda ih njuxv, lui cug oci wso ijig od Warena 4.1 ki yu wemg ov cti sesapciyxs phai abk pda oda og Fidaze 0.0 zu ya ib.
Key points
By using @Binds, Dagger generates fewer and shorter files, making the build more efficient.
Dagger @Modules allow you to provide existing objects, but you need to pass an instance of them to the @Component builder that Dagger generates for you.
@BindsOptionalOf allows you to have optional bindings.
You can provide different implementations for the same type by using @Named.
Custom qualifiers allow you to provide different implementations for the same type in a type-safe way.
From Android Studio 4.1, you can easily navigate the dependency graph from the editor.
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.