Dagger 2 Tutorial for Android: Advanced – Part 2
In this tutorial, you’ll learn how to implement advanced features of Dagger 2 by using subcomponents, custom scopes and multibinding. By Massimo Carli.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Dagger 2 Tutorial for Android: Advanced – Part 2
30 mins
- Getting Started
- Managing Multiple @Scopes
- Exploring @Singleton
- Using @Singleton
- Creating a Feature @Component
- Managing @Component Dependencies
- Creating Your Custom @Scope
- Dependencies Between Differently-Scoped @Components
- Injecting With a Custom @Component
- Connecting the Custom @Scope
- Component Dependencies With @Subcomponent
- Migrating to @Subcomponent
- @Component Dependencies Versus @Subcomponent
- Multibinding in Dagger
- Adding Different Implementations
- Implementing Multibinding
- Getting Dagger to Use the Multibinding Implementation
- Where to Go From Here?
Implementing Multibinding
This wasn't really multibinding – you just created another provider, like before! You defined a new dependency as usual, with an object of type Set<NewsStats>
.
However, multibinding allows you to do more.
Suppose you want a new feature that defines and uses its own NewsStats
. One option is to add an instance of the new class into the StatsModule
. However, this would break the principle of separation of concern and make the code brittle, as only the new feature should care about providing the dependency.
To communicate the new NewsStats
to Dagger, start off by creating a new package named thirdparty. Then create WordCountNewsStats.kt in the new thirdparty package, with the following code:
class WordCountNewsStats : NewsStats {
override fun printStats(news: News) {
val wordsCount = news.body.splitToSequence(" ").count()
Log.i(STATS_LOG, "News Word count: $wordsCount")
}
}
Getting Dagger to Use the Multibinding Implementation
Now you need to tell Dagger that you want to add this implementation to the Set<NewsStats>
it provides.
You will do this by creating a new @Module
implementation. Define a ThirdPartyStatsModule.kt in the same thirdparty package:
@Module
class ThirdPartyStatsModule {
@Provides
@IntoSet // HERE
fun provideWordsCountNewsStats(): NewsStats = WordCountNewsStats()
}
Note that provideWordsCountNewsStats()
doesn't return a Set<NewsStats>
, but rather an object of type NewsStats
. Using @IntoSet
, you inform Dagger that you want to contain that instance in the Set<NewsStats>
Dagger injects.
Now you need to add the ThirdPartyStatsModule
to the FeatureComponent
:
@Subcomponent(
modules = [
FeatureModule::class,
StatsModule::class,
ThirdPartyStatsModule::class // HERE
]
)
@FeatureScope
interface FeatureComponent {
- -
}
You added the ThirdPartyStatsModule
to the component, so that you include the new NewsStats
implementation in the dependency graph.
Build and run and you'll get another error. Dagger is complaining about a double binding for Set<NewsStats>
.
That's because it doesn't know that the previous is a part of a multibinding definition. You can fix this using another important annotation in StatsModule
:
@Module
class StatsModule {
@Provides
@ElementsIntoSet // HERE
fun provideNewsStats(): Set<NewsStats> = setOf(
LengthNewsStats()
)
}
Using @ElementsIntoSet
, you're telling Dagger that the Set<NewsStats>
you're providing is part of a multibinding that other modules can contribute to.
Now, build and run. Open News Details and check the LogCat that contains output like this:
I/NEWS_STATS: News Word count: 153 // HERE
I/NEWS_STATS: News Length: 1013
The new NewsStats
is now part of Set<NewsStats>
. All of the NewsStats
implementations, which are built into the set, are part of the same set of the depdendency type. Then when you inject the set, you get all of the implementations of the same type, within the set!
Multibinding is a very powerful tool, but it only works with Set
s and Map
s. This causes extra work if you want to force the items to display in a specific order.
Congratulations! You've completed this tutorial and learned more about how to use Dagger. :]
Where to Go From Here?
Download the end project using the Download Materials button at the top or bottom of this tutorial.
In this tutorial, you learned how to create a custom @Scope
to manage dependency lifecycle and how to organize the code to manage dependencies between different @Component
s. You also had the chance to see how multibinding works!
You're a Dagger expert now, but the library evolves continuously. Google is working hard to resolve the dependency cycle problem with @Component
and @Subcomponent
dependencies. Stay tuned for updates on raywenderlich.com.
I hope you found this tutorial helpful! If you have any comments or questions, feel free to join in the forum discussion below.