DI is a pattern to decouple your code. You don’t need to have a DI framework to handle the injection, but using such will make your application better. Things like singleton and initialization. Let’s see how to do that in Android using Dagger. Even you don’t what DI is, we will go through it pretty fast and clear. We will use Kotlin, plain Dagger and Android Studio here.
This is a setup with plain dagger, if you want to see how to setup with
dagger-android, you should check this blog. But if you are pretty new to dagger. I strongly suggest to start with the plain dagger.
Here, we are starting from a new project created from Android Studio. The goal of the blog is to add application wide dependencies. Things like your HTTP client or SQL Lite things which you will use through most of your activities.
It is a way that a
class A could consume another
class B as a dependency without worrying initialization details about that
class B. Something like this:
Of course, you can create the instance of
staff inside this
Company class. But what about there are different subclasses of this
Staff class which requires different signature for initialization? Or the signature for the constructor just changes in the future. Then you have to change every where where this
staff gets initialized. With the code above, the company don’t need to know how to initialize the
staff, it just needs to consume.
Here, we say, the
Staff classhas been
Company classas a dependency.
Actually, DI library will handle more things for you. Something like dependency chain. Where you need to create instance A in order to create instance B, then there is another instance C depends on instance B. And your
onCreate method just got bloated by this.
And now you see the pattern here. You need to prepare these initialization of dependencies somewhere therefor you can use them later. So here, in dagger’s terms:
- You declare how to generate these dependencies in
- You use
@Componentto connect the dependencies with their consumers.
- Then inside the consumer class. You
daggerwill create the instances for from the
app, add the following settings in addition to your current gradle settings.
What is that
kapt? Well, Dagger requires an annotation processor. For Java you use the Groovy methods
apt or the newer
annotationProcessor, while you need to use
kapt for Kotlin. And it’s been provided by that
MyRepo simply needs the
context to start with, and will return some string based on the
context. After knowing how to inject this, you should handle most cases with ease.
So, add a file named
MyRepo.kt with the following code:
Then we will use this
MyRepo in the
MainActivity to show the string in the console.
There is no such thing like auto-create, you need to manually write the creation and let
dagger invoke it when it tries to inject the dependencies(consider this as auto creation). So, a
@Module is for handling such cases where you write function to create all the instances.
You see, we inject the
application into this
MyAppModule for it to create an instance of
MyRepo. It is easy to understand.
@Module: to mark a class as
@Provides: to indicate this is where the dependency gets created, it’s been provided by this method.
- The name of the method doesn’t matter. The type matters.
provideBlahBlahis just a convention people use all the time when using
- The name of the method doesn’t matter. The type matters.
@Singleton: to indicate this instance will be a singleton which always will give the same instance of class.
Before you just use the
@Module as a repo for all the
dependencies. You need to create a
dagger Component which behaves like a middle layer between the
moduel and actual consumer.
Create a new file with the following code:
The code means, it will use the
MyAppModule as a source
module and inject
MainActivity with it.
modules = [MyAppModule::class]this is an array, which means you can add more
moduleshere as a starting point rather than just one.
- You can add new method like
fun inject(target: SecondActivity)to support new activity
Create a file named
MyApp.kt with the following code:
And add it to the
Now you have the module, you have to initialize it somewhere in order to use it later. Consider this is an appllication wide
module, we will do the preparation in the
Now modify your
MyApp class to the following:
Here you initialize the an instance of
MyAppComponent by yourself. Remember the
MyAppComponent is an interface? The implementation will then be generated for you.
Here, the dependency will be created in the
initDagger method which will be invoked in the
Look at this
.myAppModule(MyAppModule(app)), remember we declared a parameter for the constrcutor of
MyAppModule? It needs an
application, now have to do pass it.
You may notice that the Android Studio may tell you that
unresolved reference DaggerMyAppComponent. It’s fine. You can just click the
Build from the menu, and click
Make module app from the dropdown menu.
Then a java file will be generated for you. And this problem will be resolved. If not works, go back to step 2 to see what you are missing.
DaggerMyAppComponentmatters, you need to change according to your component name. If your application component is named as
ABCComponent, then you need to change it to
DaggerABCComponent. As well as that
.myAppModule(MyAppModule(app)). You need to adjust the
.myAppModule()to your case.
make module app, the
.myAppModule will likely to have a deprecated warning. It’s fine too, it just indicates it gets no usage. After the following steps, it will gone.
So far, we have created the dependencies and initialized it in
MyApp. Now we will inject it. Open the
MainActivity.kt and add the following code:
So, what happens here.
- We create the property
myRepothat will hold the dependency.
- And the decorator
@Injectwill let dagger knows that you want it to be injected.
- Then, in the
onCreate, you start the injection with
(application as MyApp).myAppComponent.inject(this).
- And there is no magic here, the
inject(this)already got its declaration in that
interface MyAppComponent, remember? :)
- Dagger will then look through all
@Moduleto find one function that has a matched return type.
- Then you get your instance.
You should see the output in the console:
You can find the repo here:
There are more things to learn. But I think you have a good start. Hope it helps.
If you want to see how to setup with
dagger-android which is another package from Google, you should check this blog. It designs to be more