Jens Klingenberg

How to get started with Dagger 2 on Android

Posted on July 12, 2018  •  4 minutes  • 658 words
Table of contents

This is a small example on how to get started with Dagger 2. I will explain how to create a component that will provide an instance of an Retrofit Api. Please check out my example Github project

If you have absolutely no idea what Dependency Injection and Dagger is, take a look at:

1) Add Dependencies

//Dagger Dependencies
implementation "com.google.dagger:dagger-android:2.15"
implementation "com.google.dagger:dagger-android-support:2.15"

// if you use the support libraries
kapt "com.google.dagger:dagger-android-processor:2.15"
kapt "com.google.dagger:dagger-compiler:2.15"

These are the dependencies just for Dagger2. If you want to follow this tutorial you also need to add Retrofit and RxJava. Take a look at build.gradle .

2) Create a Retrofit interface

I will use https://jsonplaceholder.typicode.com in this example. If you don't know how to use Retrofit, i already explained it here.
interface TestApi {
  @GET("posts")
  fun getPostList(): Single<Response<List>>
}

data class Post(
    val id: Int? = null,
    val title: String? = null,
    val body: String? = null,
    val userId: Int? = null
)

3) Create a Module

Create AppModule

@Module
class AppModule(private val application: Application) {
  @Provides
  @Singleton
  fun provideContext(): Application = application
}

A module is a class which is annotated with @Module. A module contains functions which provide/create the needed instances of your dependencies.

In this example the provideContext() will provide an instance of Application wherever Dagger is used to provide it.

Dagger detects that with help of the @Provides annotation and the return type of the function. @Singleton annotates that the provided object will be used as an Singleton. The name of the function is irrelevant.

Create RemoteModule

Let’s create a second module which will provide the Retrofit Api instance. You could use one big module, but it’s better to organize your dependencies in separate modules.

@Module
class RemoteModule {
  @Provides
  @Singleton
  fun provideTestApi(retrofit: Retrofit) = retrofit.create(TestApi::class.java)
  
  @Provides
  @Singleton
  fun provideRetrofit(): Retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .baseUrl("https://jsonplaceholder.typicode.com")
    .build()
}

provideTestApi() will provide the needed instance of your Retrofit interface. As you can see the function needs a Retrofit object, Dagger will automatically detect that provideRetrofit() will provide the needed instance and use it.

3) Create a Component

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

Create a Component to bundle your modules A Component is an interface annotated with @Component and the array of modules that this component should contain.

4) Initialize Dagger Components

class App : Application(){
    companion object {
        lateinit var instance: App
        lateinit var appComponent: AppComponent
    }
    fun initializeDagger() {
        appComponent = DaggerAppComponent.builder()
            .appModule(AppModule(this))
            .remoteModule(RemoteModule())
            .build()
    }
    override fun onCreate() {
        super.onCreate()
        initializeDagger()
        instance = this   
    }
}

Now you need to initialize your Dagger Components. Note: Don’t wonder that the DaggerAppComponent is missing, it will be automatically generated when you run “Build Project”. Dagger uses this pattern Dagger+“Name of your component class”. So if you would rename AppComponent to MyAppComponent it will generate a DaggerMyAppComponent.java class. Dagger will also generate corresponding functions to the builder for every module that is annotated in your component. In this functions you need to pass a object of your module.

5) Use Dagger

class MainActivity : AppCompatActivity() {

  @Inject
  lateinit var testApi: TestApi

  private fun initializeDagger() = App.appComponent.inject(this)

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

    testApi.getPostList()
    ....

  }
}

Let’s say you want to use the TestApi in your MainActivity To tell Dagger to provide dependencies you first need to inject your appComponent. You do this by adding a function that takes a MainActivity as a parameter to your component .

@Component(modules = [(AppModule::class), (RemoteModule::class)])
@Singleton
interface AppComponent {
  fun inject(mainActivity: MainActivity)
}

Now you can use this function in your MainActivity

private fun initializeDagger() = App.appComponent.inject(this)

Make sure to initialize Dagger before you use injected dependencies

Every dependency inside this class that is annotated with @Inject will be provided by your Dagger modules.

I hope this blog post helped you to setup a basic project

If you want to do more advanced stuff with Dagger, check out the documentation

Other useful resources:

Example Project on Github

Documentation

Let's connect: