7 steps to implement Dagger 2 in Android
So I finally got a chance to explore the new Dagger 2 in a project recently. And while there are a lot of resources online about what is Dagger and why dagger 2 is necessary and how to implement Dagger 2, I found that there was a steep learning curve to it. While I understood why dagger 2 is not only necessary but a must in some cases, I found practical implementation difficult. So I thought I would write about the 7 basic steps to implement Dagger 2 in an Android app.
Note: This article focuses on implementation of dagger using the new dagger android injection.
I chose to build a simple movies app to test the dagger implementation. This is the app.
This app displays a list of movies or tv shows from the famous TMDB api. There is a details page which displays the movie or tv show videos, reviews, cast and crew info etc. We are going to build a simplified version of this app. i.e. we are going to focus on building a single screen app that fetches a list of movies from the TMDB api and displays it in the app.
For those of you interested in skipping the article, the GitHub link is for this implementation is here.
- The master branch — code in Java
- The kotlin_support branch — code in Kotlin
So let’s begin!
Step 1: Add the necessary dependencies to the app
Java:
Kotlin:
Step 2: Configure Room
Next thing we have to do is setup Room database in the app. This involves:
1. Creating an Entity:
MovieEntity.java:
MovieEntity.kt:
2. Creating Dao class:
MovieDao.java:
MovieDao.kt:
3. Creating the Database:
AppDatabase.java:
AppDatabase.kt:
Note: If you would like to know more about Room persistence Library and how to configure it, then checkout this article
Step 3: Configure Api Service:
Now that we have setup the local database, we need to configure the api service system. We are going to use Retrofit for that. This involves:
1. Creating a rest api response model:
MovieApiResponse.java:
MovieApiResponse.kt:
2. Creating a rest api service:
MovieApiService.java:
MovieApiService.kt:
Step 4: Configure Repository class
The repository classes are responsible for handling data operations. For instance, the first time the app is opened, the data will be fetched from the backend api service and stored locally in room. But if there is no internet or the api service is down, the data will be fetched from the local cache. So this class will choose which data sources to use to get the data.
MovieRepository.java:
MovieRepository.kt:
Step 5: Configure the ViewModel class
As mentioned in the previous step:
- The repository class is responsible for fetching the data (either from web api or local cache).
- The ViewModel is responsible for updating the UI with the data changes. The ViewModel will initialise an instance of the Repository class and update the UI based with this data.
For this, the ViewModel must have access to the usingMovieDao
class and the MovieApiService
class. This is where Dagger comes in. We will be injecting the ViewModel with the MovieDao
class and the MovieApiService
class.
Now, let’s setup the ViewModel class.
MovieListViewModel.java:
MovieListViewModel.kt:
Step 5: Configure Dagger (finally!)
Now let’s create some Dagger classes.
In Dagger, we can annotate classes with @Module
. These classes are responsible for providing objects/classes which can be injected. Such classes can define methods annotated with @Provides
. The returned objects from these methods are available for dependency injection.
So in our case, we need to inject two classes: MovieDao
class and MovieApiService
class. So we are going to create two Modules: ApiModule
and DbModule
(This can be done in a single module but I prefer to keep local and web service separate).
1. ApiModule class
ApiModule.java
ApiModule.kt
2. DbModule class
DbModule.java
DbModule.kt
3. ViewModelFactory class:
Now we need to inject these two modules into our ViewModel
. ViewModelFactory
class basically helps you dynamically create ViewModels for your Activities and Fragments. The ViewModelFactory
class has a list of providers and can create any ViewModel
that was bound. Fragments and Activities can now just inject the factory and retrieve their ViewModel
.
ViewModelFactory.java
ViewModelFactory.kt
4. ViewModelKey class:
ViewModelKeys
helps you map your ViewModel
classes so ViewModelFactory
can correctly provide/inject them.
ViewModelKey.java
ViewModelKey.kt
4. ViewModelModule class
The ViewModelModule
is used to provide a map of view models through dagger that is used by the ViewModelFactory
class.
ViewModelModule.java
ViewModelModule.kt
So basically,
- We can use the
ViewModelModule
to define ourViewModels
. - We provide a key for each
ViewModel
using theViewModelKey
class. - Then in our Activity/Fragment, we use the
ViewModelFactory
class to inject the correspondingViewModel
. (We will look into more detail at this when we are creating our Activity).
5. ActivityModule class
Since we are using the dagger-android support library, we can make use of Android Injection. The ActivityModule
generates AndroidInjector
(this is the new dagger-android class which exist in dagger-android framework) for Activities defined in this class. This allows us to inject things into Activities using AndroidInjection.inject(this)
in the onCreate()
method.
ActivityModule.java
ActivityModule.kt
Note: We can define all of the Activity which require injecting. For instance, in our case, this will generate
AndroidInjector<MainActivity>
.
6. AppComponent class
Any class with the annotation @Component
defines the connection between the modules and the classes which need the dependency. We define a @Component.Builder
interface which will be called from our custom Application class. This will set our application object to the AppComponent
. So inside the AppComponent
the application instance is available. So this application instance can be accessed by our modules such as ApiModule
when needed.
AppComponent.java
AppComponent.kt
Step 6: Configure Application class
So now we create a custom Application class in our project.
AppController.java
AppController.kt
Note: Don’t forget to add this custom Application class to the AndroidManifest.xml
<application
android:name=".AppController"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"/>
Step 7: Configure MainActivity class
So now we need to create our Activity class.
MainActivity.java
MainActivity.kt
Note: I am not including the implementation of the xml classes or the RecyclerView adapter classes here as it is not part of the scope of this article. You can checkout this Github project to know the detailed implementation.
And that’s it! We build and run our app and this is the output we should receive.
Note: If you would like to know how to implement the
BackgroundSwitcherView
i.e. change the background of the activity when the recyclerView is scrolled, checkout this link.
Bonus:
We saw how to inject the ViewModelFactory
into our MainActivity
. If you would like to inject the ViewModelFactory
into a Fragment, we need to do the following modifications:
1. FragmentModule class:
Create a new class called FragmentModule
.
FragmentModule.java
FragmentModule.kt
2. Modify ActivityModule class:
Add the newly created FragmentModule
to whichever Activity you want to inject. i.e. in our case MainActivity
.
ActivityModule.java
ActivityModule.kt
3. Modify MainActivity class:
We need to implement HasSupportFragmentInjector
in our Activity if we want to inject the ViewModelFactory
class in our Fragment. And also, move all our RecyclerView.Adapter
and ViewModel
implementation to the Fragment class.
MainActivity.java
MainActivity.kt
4. Add MovieFragment class:
Lastly, we need to create our Fragment class. We inject the ViewModelFactory
into the Fragment and initialise the viewModel. The remaining implementation is the same.
MovieListFragment.java
MovieListFragment.kt
5. Add FragmentModule class to AppComponent:
@Component(
modules = [
ApiModule::class,
DbModule::class,
ViewModelModule::class,
ActivityModule::class,
FragmentModule::class,
AndroidSupportInjectionModule::class]
)
You can checkout this commit to find out the differences between injecting into Activity and injecting into fragment for Java and this commit for Kotlin.
And that’s it! 😄. I know it feels overwhelming and kinda a lot of work but in the end it’s worth it, I think.
You can find the GitHub link for this sample implementation here:
- The master branch — contains Dagger implementation in Activity in Java.
- The kotlin_support branch — contains Dagger implementation in Activity in Kotlin.
Fragment injection implementation can be found under:
- inject_into_fragment_dagger_java — contains Dagger implementation in Fragment in Java.
- inject_into_fragment_kotlin — contains Dagger implementation in Fragment in Kotlin.
For those of you interested in the whole app implementation, (and not just the simplified version we implemented here), you can checkout the Github project from here.
The master branch — code in Java
The kotlin_support branch — code in Kotlin
I hope you enjoyed this article and found it useful, if so please hit the Clap button. Let me know your thoughts in the comments section.
Happy coding! Thanks for reading!