Dependency Injection in Android with Dagger 2 and Kotlin
In this Android with Kotlin tutorial, you’ll learn about dependency injection and how to make use of the Dagger 2 Java/Android framework for this purpose. By Dario Coletto.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Dependency Injection in Android with Dagger 2 and Kotlin
30 mins
- Introduction
- What is Dependency Injection?
- Practical example of Dependency Injection
- The Dependency Inversion Principle
- How can Dagger 2 help with DI
- Getting Started
- MVP
- Dependencies in DroidWiki
- Configure the Project With Dagger 2
- Dagger 2 public APIs
- Module
- @Provides and @Singleton
- Component
- Your first (dependency) injection
- Update HomepageActivity
- The General Pattern
- Injecting the Network Graph
- NetworkModule
- Simplifying API builder
- WikiModule
- Update PresenterModule
- Update WikiApi
- Where to Go From Here?
MVP
In case you’re unfamiliar with the MVP pattern, there are many good online resources for getting started.
MVP is similar to other structural patterns for implementing separation of concerns. Examples are Model-View-Controller and Model-View-ViewModel. In MVP on Android, your activities and fragments typically act as the view objects. They do so by implementing a view interface and handling interaction of the app with the user.
The view passes on user actions to the presenter, which handles the business logic and interaction with data repositories, such as a server API or database. The model layer consists of the objects that make up the content of the app.
In the case of DroidWiki, the HomepageActivity
class implements the HomepageView
interface. HomepageActivity
has a reference to a HomepagePresenter
interface. This controls access to model objects of type Homepage
The use of OkHttp 3 is found in the WikiApi
class in the network
package. This class defines the interface to the WikiMedia API required by the app. There are two calls of type GET defined and the JSONObject
will let you parse the obtained responses. The parsing will be executed in the HomepageResult
and the SearchResult
classes. And you will get a WikiHomepage
object and a list of Entry
objects.
Note: Since Kotlin doesn’t need you to write getters and setters, you can replace POJO classes with a data class
. For more information, see the official kotlin data classes documentation.
Note: Since Kotlin doesn’t need you to write getters and setters, you can replace POJO classes with a data class
. For more information, see the official kotlin data classes documentation.
Dependencies in DroidWiki
Open the HomepageActivity
class in the ui.homepage
package. In its onCreate()
method, there are several calls to configure a HomepagePresenter
:
private val presenter: HomepagePresenter = HomepagePresenterImpl()
...
presenter.setView(this)
presenter.loadHomepage()
Here, you create a concrete implementation of a HomepagePresenter
when the activity is instantiated.
Open HomepagePresenterImpl.kt and take a look at loadHomepage()
. Both an OkHttpClient
object and a WikiApi
object are created and configured in the loadHomepage()
method. The same happens for the SearchActivity
with an EntryPresenter
and a list of EntryView
.
This creation of dependencies couple the model, view, and presenter layers too tightly. Swapping in a mock presenter for the view is impossible as written without updating the view code. The code for creating the OkHttpClient
and WikiApi
objects is repeated between the two presenter implementations in the app: HomepagePresenterImpl
and EntryPresenterImpl
.
Finally, it’s time to start writing some code to remove code duplication and some coupling between layers!
Configure the Project With Dagger 2
Configuring Dagger with Kotlin is a little bit different from how you may have done with Java.
Dagger requires an annotation processor, and thus the main difference is which one you are going to use. In fact with Java you used the Groovy methods apt
or the newer annotationProcessor
, while with Kotlin you need to use kapt
.
By default kapt is not enabled in Kotlin, and to enable it you must apply its plugin to your app build.gradle, so add the line apply plugin: 'kotlin-kapt'
:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
// Add this line to enable kapt
apply plugin: 'kotlin-kapt'
...
Then add these dependencies to actually “install” dagger
dependencies {
...
implementation 'com.google.dagger:dagger:2.11'
kapt 'com.google.dagger:dagger-compiler:2.11'
provided 'javax.annotation:jsr250-api:1.0'
...
}
Here we’re using Dagger 2.11, you can check the latest version in the Maven repository.
Android Studio will prompt you to sync your gradle files on this change, so please go ahead and do so to ensure that you’re including Dagger correctly. Notice that you are including an annotation library from javax
, because many of the features of Dagger are provided by Java annotations.
Dagger 2 public APIs
Dagger 2 can seem complex at the beginning, but it’s really not so hard. In fact, the complete public API of Dagger is composed by less than 30 lines of code. And from these lines you can remove a pair of interfaces that are rarely used (Lazy and MapKey), so the most used public APIs are composed of 3 annotations:
public @interface Component {
Class<?> [] modules() default {};
Class<?> [] dependencies() default {};
}
public @interface Module {
Class<?> [] includes() default {};
}
public @interface Provides {}
Now let’s see how these annotations are used to bring dependency injection to your projects!
Module
The first annotation you’ll use is the @Module
annotation. Start by creating a new package named dagger
under the app main package, by right-clicking the main package and selecting New/Package:
Next, create a new file in the dagger
package. Right-click dagger and select New/Kotlin File/Class. Name the class AppModule
.
Add the following empty class to the new file:
@Module
class AppModule {
}
Here, you’ve created a class named AppModule
and annotated it with the Dagger @Module
annotation. Android Studio should automatically create any necessary import statements for you. But if not, hit option+return on Mac or Alt+Enter on PC to create them as needed.
The @Module
annotation tells Dagger that the AppModule
class will provide dependencies for a part of the application. It is normal to have multiple Dagger modules in a project, and it is typical for one of them to provide app-wide dependencies.
Add that capability now by inserting the following code within the body of the AppModule
class:
@Module
class AppModule(private val app: Application) {
@Provides
@Singleton
fun provideContext(): Context = app
}
You’ve added a private field to hold a reference to the app
object, a constructor to configure app
, and a provideContext()
method that returns the app
object. Notice that there are two more Dagger annotations on that method: @Provides
and @Singleton
.
@Provides and @Singleton
The @Provides
annotation tells Dagger that the method provides a certain type of dependency, in this case, a Context
object. When a part of the app requests that Dagger inject a Context
, the @Provides
annotation tells Dagger where to find it.
Note: The method names for the providers, such as provideContext()
, are not important and can be named anything you like. Dagger only looks at the return type. Using provide
as a prefix is a common convention.
Note: The method names for the providers, such as provideContext()
, are not important and can be named anything you like. Dagger only looks at the return type. Using provide
as a prefix is a common convention.
The @Singleton
annotation is not part of the Dagger API. It’s contained inside the javax package you added to your build.gradle at the beginning. It tells Dagger that there should only be a single instance of that dependency. So when generating the code Dagger will handle all the logic for you, and you won’t write all the boilerplate code to check if another instance of the object is already available.