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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

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&ltNewsStats&gt.

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&ltNewsStats&gt 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&ltNewsStats&gt, but rather an object of type NewsStats. Using @IntoSet, you inform Dagger that you want to contain that instance in the Set&ltNewsStats&gt 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&ltNewsStats&gt.

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&ltNewsStats&gt 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

RwNews App

RwNews App

The new NewsStats is now part of Set&ltNewsStats&gt. 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 Sets and Maps. 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 @Components. 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.