Chapters

Hide chapters

Dagger by Tutorials

First Edition · Android 11 · Kotlin 1.4 · AS 4.1

8. Working With Modules
Written by Massimo Carli

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... 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.

Unlock now

In previous chapters, you’ve used @Modules as a way to give Dagger information it can’t get from the code itself. For instance, if you define a dependency using an abstraction type, like an interface or abstract class, you need a way to tell Dagger which implementation to use with @Binds. If you want to provide the instance for a given type yourself, you can use @Provides instead.

But you can use @Modules for more than that. As the name implies, they’re also a way to group definitions. For instance, you might use @Modules to group different @Components depending on their scope.

Your app will probably have different @Modules and you need a way to give them structure. @Modules can have dependencies as well.

In this and the next chapter, you’ll learn everything you need to know about @Modules. In this chapter, you’ll learn how to:

  • Use different Dagger @Modules in the same app.
  • Optimize start-up performances using Dagger’s Lazy<T> interface.
  • Avoid cycled dependencies using the Provider interface.
  • Use optional bindings.

As you see, there’s a lot to learn about @Modules.

Note: In this chapter, you’ll continue working on the RaySequence app. After the next chapter, you’ll have all the information you need to migrate the Busso App to Dagger.

Throughout the chapter, you’ll change configurations often. You don’t need to stop to build and run the app to prove that everything still works after every change.

Why use modules?

According to the definition in the @Module documentation, a @Module annotates a class that contributes to the object graph.

Note: It’s easy to confuse a Dagger @Module with the concept of a Module in a project. You’ll see a note like this when there’s possible ambiguity.

The definition uses the term class, but there are different ways to define a @Module, as you’re about to see. In Android Studio, open the RaySequence project from in the starter folder of the materials for this chapter. Now, open AppModule.kt in the di package and look at the following code:

@Module
object AppModule {

  @Provides
  fun provideSequenceGenerator(): SequenceGenerator<Int> =
      NaturalSequenceGenerator(0)

  @Module
  interface Bindings {

    @Binds
    fun bindSequenceViewBinder(impl: SequenceViewBinderImpl): SequenceViewBinder

    @Binds
    fun bindSequencePresenter(impl: SequencePresenterImpl): SequencePresenter

    @Binds
    fun bindViewBinderListener(impl: SequencePresenter):
        SequenceViewBinder.Listener
  }
}

As mentioned in the previous chapter, this is just a way to define some @Binds and @Provides functions in the same file. These are actually two different modules. You can prove this by opening AppComponent.kt in the same di package:

@Component(
    modules = [
      AppModule::class,
      AppModule.Bindings::class
    ]
)
@Singleton
interface AppComponent {

  fun inject(mainActivity: MainActivity)
}

The modules attribute for the @Component annotation accepts an array of KClass<*>. In the previous code, AppModule and AppModule.Bindings are related, giving you a simple way to improve the code. In AppModule.kt, replace AppModule’s header with this:

@Module(includes = [AppModule.Bindings::class]) // HERE
object AppModule {
  // ...
}

@Module has an includes attribute that allows you to do what the name says: Including AppModule.Bindings in AppModule lets you replace the @Component header in AppComponent.kt with this:

@Component(modules = [AppModule::class]) // HERE
@Singleton
interface AppComponent {
 // ...
}

This is a small step that helps organize the code in your project.

Using multiple @Modules

To make your code easier to read, split the definitions in AppModule.kt into two. Create a new file named AppBindings.kt in the di package and add the following code:

Using an abstract class

AppBindings.kt contains an interface with some operations but nothing’s stopping you from using an abstract class instead. To do so, change the AppBindings code like this:

Zujibe 7.5 — Yaravuaq yan lyi qite Jukkas wuzapuxal
Nitoxa 3.5 — Heyowoir foy wbi xago Dowrur miriyaxul

Using a concrete class

What about AppModule? It contains a concrete function because you explicitly created the instance of NaturalSequenceGenerator as an implementation of the SequenceGenerator<Int> interface you use as a type of the dependency. In the previous code, you used an object but there’s no reason not to use a class instead.

Zoxiqo 0.5 — Cuvixajiv kuja kah rfe OscZukeso
Hicadu 6.2 — Hemerajoq xaki nup rco IxxHilodi

Wokevu 4.2 — Ztoy Cenkiy Nwnepeso atmiuh oc Axpkior Pvajao
Ruzake 0.3 — Ybel Tuxsop Fjyaboga irnoev is Usdzuud Rqizuo

Buricu 6.6 — Lorpes Hqquxece Jaddij
Legiwu 6.3 — Yohwac Dbmuyoyi Moclax

Rofuxi 4.1 — Nixsam yawa zomikwibih alca Qoya saja
Vatile 6.3 — Tesbuh roka qecoyharip ewta Maxi tebe

Using a companion object

Earlier, you tried to define a @Module using an abstract class and you got an error saying that you could only do that using a static function. To fix the problem, you need a companion object. Functions or properties declared in companion object are tied to a class rather than to instances of it.

Using Dagger’s Lazy interface

In the previous paragraphs, you saw that @Module contains information about how to create an instance of an object in the dependency graph. Dagger created the object instance as soon as the @Component was built or created. However, this operation can impact the cold start time of the app.

Mutiya 4.2 — Iba XovLeh le manhuq kti Rqugvet nafu rit dju avx
Mibala 5.3 — Ewu DulXen yi digfac nsu Wvarxem ziqe wec rbo atb

Lilisi 1.9 — Baceqv ngo qijbsxanw feayy juwoezt
Seroyu 0.8 — Coyuws kji qaqydhuqp saift rejuuyn

Resolving cycled dependencies

RaySequence uses the small mvp library you already saw in the previous chapters. In that library, the relationship between the presenter and the viewBinder happens through the bind()/unbind() functions. This is how you pass the reference of the SequenceViewBinder implementation to the implementation of SequencePresenter into MainActivity, as you see in this code:

Adding a new implementation

Create a new file named CycledSequencePresenter.kt in RaySequence’s presenter and add the following code:

Telling Dagger to use the new implementation

Now, you need to tell Dagger to use this implementation instead of SequencePresenterImpl. Open AppBindings.kt and replace @Binds in the SequencePresenter interface with this:

Encountering a cycled dependency error

You can now build the app — but something’s wrong. Dagger is complaining, giving you this error:

Niqetu 6.6 — Ndhhi hewokzafyl
Cavahi 5.2 — Kwpye nisarrommy

Resolving the problem with Lazy

Open CycledSequencePresenter.kt and change it like this:

Solving the dependency problem with Provider

In the previous paragraph, you broke a cycle dependency using Lazy<T>. As you saw, that interface is a possible solution for a specific performance problem. The reason Lazy<T> helped break the cycle is that it allows you to defer the creation of an instance Dagger needs in the binding of a dependency.

Key points

  • A @Module can include other modules by using the includes attribute.
  • When you define a @Module with an interface or an abstract class, it doesn’t change the code Dagger generates.
  • Dagger parses the Java equivalent of your Kotlin to generate its code.
  • Don’t confuse the Kotlin Lazy<T> with Dagger’s dagger.Lazy<T>.
  • dagger.Lazy<T> lets you defer creating an object of the dependency graph.
  • dagger.Lazy<T> is not a scope.
  • You can break cycle dependencies using the Provider<T> interface.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

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.

Unlock now