The dagger.android Missing Documentation
Tags: dagger, dagger2, android, dependencyinjection
Published: 2018-04-17 21:25:50

---
title: The dagger.android Missing Documentation
published: true
description: a pointed tutorial
tags: dagger, dagger2, android, dependency injection
cover_image: https://i.imgur.com/3aV2l9q.png
---
# No thermosiphons here!

1. This part
2. [Part 2 — ViewModels and View Model Factories](https://dev.to/autonomousapps/dagger-dot-android-part-2-viewmodels-and-viewmodel-factories-10ii)
3. [Part 3 — Fragments](https://dev.to/autonomousapps/the-daggerandroid-missing-documentation-part-3-fragments-12go)

So you want to use [dagger.android](https://google.github.io/dagger/android), Dagger2's (relatively) new package aimed specifically at you, The Android Developer, but are confused by the lack of [thermosiphons and coffee makers](https://i.imgur.com/iP52Th1.png) in the official documentation. What's a dev to do?

![Finding thermosiphons](https://i.imgur.com/z3i2qQ4.png)

I've got you covered. This is a continuation of my series on [rewriting Chess.com's Android app](https://dev.to/autonomousapps/rewriting-chesscoms-android-app-4aij). I try to be thorough, but if it turns out I skimmed over something, please let me know in the comments.

Let's get started!

# Project setup
Add the following to your `app/build.gradle` file
```groovy
// If you're using Kotlin
apply plugin: 'kotlin-kapt'

dependencies {
  // ...all the libs...

  // Dagger
  def dagger_version = "2.15"
  // Required
  implementation "com.google.dagger:dagger-android:$dagger_version"
  kapt "com.google.dagger:dagger-android-processor:$dagger_version"

  // Required if you use anything prefixed with AppCompat or from the support library
  implementation "com.google.dagger:dagger-android-support:$dagger_version"
  kapt "com.google.dagger:dagger-compiler:$dagger_version"

  // Required if you care about testing, and of course you care about testing. Required.
  kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version"
  kaptAndroidTest "com.google.dagger:dagger-android-processor:$dagger_version"
}
```

# Injecting your custom Application

Create a custom Application class, call it (say) `MainApplication`, and make it look like this:

```kotlin
// open because we will have a DebugMainApplication for testing
open class MainApplication : Application(), HasActivityInjector {

  // Required by HasActivityInjector, and injected below
  @Inject
  protected lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
  override fun activityInjector() = dispatchingAndroidInjector

  override fun onCreate() {
    super.onCreate()
    initDagger()
  }

  private fun initDagger() {
    DaggerMainApplication_MainApplicationComponent.builder()
      .app(this)
      .build()
      .inject(this)
  }

  // Doesn't need to be a nested class. I could also put this in its own file or,
  // this being Kotlin, in the same file but at the top level.
  @Singleton
  @Component(modules = [
    // provided by dagger.android, necessary for injecting framework classes
    AndroidSupportInjectionModule::class,

    // Defines a series of Subcomponents that bind "screens" (Activities, etc)
    ScreenBindingModule::class,
  ])
  interface MainApplicationComponent {
    fun inject(app: MainApplication)

    @Component.Builder
    interface Builder {
      fun build(): MainApplicationComponent
      @BindsInstance fun app(app: Context): Builder
    }
  }
}
```
Here's what we've done:
1. Defined a custom `Application`,
2. that implements `HasActivityInjector`,
3. that defines the root/global/singleton/app component that is the parent of all of your app's subcomponents,
4. that specifies that it takes an instance of the application itself (`@BindsInstance`), which means that we now have our `MainApplication` instance available to this component and all its subcomponents.
4. And finally, built Dagger's generated implementation of that component's contract, and then used it to inject our Application with a `DispatchingAndroidInjector<Activity>`

## What is a `DispatchingAndroidInjector`?

![magic](https://media2.giphy.com/media/12NUbkX6p4xOO4/giphy.gif)

It is what ultimately injects your framework class (Activities, Fragments, Services, etc). Later on, in your Activities, you'll be calling `AndroidInjection.inject(this)`, and this makes use of the `DispatchingAndroidInjector` instance that your `MainApplication` provides via `HasActivityInjector`.

# ScreenBindingModule

```kotlin
// Don't worry, it'll get bigger!
@Module abstract class ScreenBindingModule {
  @ActivityScoped // optional
  @ContributesAndroidInjector(modules = [MainActivityModule::class])
  abstract fun mainActivity(): MainActivity
}
```

`ScreenBindingModule` is an abstract class annotated with `@dagger.Module`. In it, we need to add an abstract function annotated with `@ContributesAndroidInjector` for each Activity we want to inject. This function should return an instance of the activity (it doesn't actually "create" your activity; this is just how Dagger knows which class is being injected). We can optionally specify modules to install on this subcomponent, and optionally specify scopes. Each of these functions actually defines a `Subcomponent.Builder` used to inject your Activity classes; the code itself is generated by dagger. Essentially, you're going to have one function per Activity.

(PS: `@ActivityScoped` is a custom scope that you'll have to define yourself. See the full code sample linked below.)

# Injecting your `Activity`s

```kotlin
// We can define this anywhere we like, but it's convenient to include
// in the same file as the class being injected
// An object because I want to provide a static function, and it's Kotlin
@Module object MainActivityModule {
  // static because dagger can call this method like MainActivityModule.provideText(),
  // rather than new MainActivityModule().provideText()
  @Provides @JvmStatic fun provideText() = "Why, hello there!"
}

class MainActivity : AppCompatActivity() {

  @Inject lateinit var text: String

  override fun onCreate(savedInstanceState: Bundle?) {
    AndroidInjection.inject(this)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    textView.text = text
  }
}
```

The result, assuming our layout `activity_main` has a `TextView` named `textView`, is a simple screen showing the text "Why, hello there!"

> Well that's great and all, but now what? (And where's my coffee?!)

Great questions. This brings me to...

# Testing your activity

Let's assume that the string `"Why, hello there!"` could be anything; it's generated dynamically; maybe it's provided by a build script or retrieved via an API call. We don't want to rely on any of that in a test environment, and anyway, we have that API code unit-tested (right?). We just want to verify that our screen shows some text, given that the text exists. Here's one way to accomplish that.

## First, add a `DebugMainApplication`
```kotlin
class DebugMainApplication : MainApplication() {
  fun setTestComponent(component: MainApplicationComponent) {
    component.inject(this)
  }
}
```
This replaces the prod component with our custom test component (see below).

And create a debug variant of your manifest in `debug/AndroidManifest.xml`:
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.autonomousapps.daggerdotandroid">

    <application
        android:name="com.autonomousapps.daggerdotandroid.DebugMainApplication"
        android:label="@string/app_name"
        tools:ignore="AllowBackup,GoogleAppIndexingWarning"
        tools:replace="android:name,android:label"/>

</manifest>
```
Our test code will now use our special `DebugMainApplication` instead of our prod `MainApplication`.

## Write your test

```kotlin
class MainActivityTest {

  // Rules are one place where Kotlin code is uglier and more verbose than Java
  @get:Rule private var activityTestRule = ActivityTestRule(
    MainActivity::class.java,
    false,
    false
  )

  // Here we define a test component that extends our production component
  @Component(modules = [
    // Inheriting components don't inherit annotations, so we need to re-declare
    // that we want to inject framework classes
    AndroidSupportInjectionModule::class,

    // A test module defined below
    TestMainActivityModule::class
  ])
  interface TestMainApplicationComponent : MainApplication.MainApplicationComponent {

    @Component.Builder
    interface Builder {
      @BindsInstance fun app(app: MainApplication): Builder

      // This is the fruit of all our labor. We can now provide our custom text
      // (or anything more interesting!) into our dependency graph
      @BindsInstance fun text(text: String): Builder
      fun build(): TestMainApplicationComponent
    }
  }

  // This is basically the mirror image of ScreenBindingModule, but instead of
  // providing an abstract function for EVERY screen, we only need to provide
  // one for the screens that will get injected in our test
  @Module abstract class TestMainActivityModule {
    @ContributesAndroidInjector abstract fun mainActivity(): MainActivity
  }

  @Before fun setup() {
    val app = InstrumentationRegistry.getTargetContext().applicationContext as DebugMainApplication
    val mainComponent = DaggerMainActivityTest_TestMainApplicationComponent.builder()
      .app(app)

      // Neat!
      .text("I'm a test!")
      .build()
    app.setTestComponent(mainComponent)

    activityTestRule.launchActivity(null)
  }

  @Test fun verifyText() {
    onView(withText("I'm a test!")).check(matches(isDisplayed()))
  }
}
```

![passing test](https://i.imgur.com/f8pIVu9.png)

Cool beans. By the way, if you're confused that we have approximately a bajillion lines of setup code for a test that is really just one line long -- hey, welcome to the wonderful world of Android testing! Join us, it's fun. Also, a real test class would have more than one test and the ratio of boilerplate:test-code should eventually become something non-insane.

# What about fragments?
Please keep an eye on this page, because there is more to come! We'll be talking about injecting fragments, special considerations for injecting _retained_ fragments, and we'll even write a custom class for injecting `View`s! (`View`-injection is not supported out of the box by `dagger.android`, for reasons that will become clear.) We'll also see how to incorporate [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel.html)s, [ViewModelProvider.Factory](https://developer.android.com/reference/android/arch/lifecycle/ViewModelProvider.Factory.html)s, and maybe even [custom Scopes](https://github.com/google/dagger/issues/721)....

# This series
1. Basic setup (this post)
2. [Using Dagger with ViewModels and LiveData](https://dev.to/autonomousapps/dagger-dot-android-part-2-viewmodels-and-viewmodel-factories-10ii)
3. _More to come..._

# Resources
1. All the code here is available on my [Github repo](https://github.com/autonomousapps/DaggerDotAndroid)
2. [Keeping the Daggers Sharp](https://medium.com/square-corner-blog/keeping-the-daggers-sharp-%EF%B8%8F-230b3191c3f), which taught me something about scopes
3. 5-part series by Android Dialogs with Pierre-Yves Ricau on [Youtube](https://www.youtube.com/watch?v=2ICxQv9Ur60), which explained `@BindsInstance`, static provision methods, scoping, and so much more.

![coffee](https://i.imgur.com/j09P3hO.jpg)