Dagger 2 for Dummies in Kotlin (with 20 lines of code)

I am a dummy, and learning Dagger 2 is stretching my brain!! All tutorials I read introduced so many things to me at once e.g. Dependency Injection, Provider, Component, Module, Scope… my brain just exploded!!

Besides many tutorials are based on Java. Kotlin is the way of doing things today. It takes me months to digest Dagger 2 and had it done in Kotlin. So I vow to myself when I grab hold of it, I should create something really super simple one day, make this like ABC, for those out there like me looking for something like this.

To help me do so, I create what I believe as the world’s simplest Android App with Dagger 2 … Just one page, less than 20 lines 😎. (please don’t make another simpler one, let me keep one world record 😝).

Many tutorial shows pages after pages of codes, and linking relationships between classes. My brains hurts… as my stack is shallow 😝

(For the expert, I apologize for the very unconventional way of introducing Dagger 2, as this is really for dummies, and assume minimal knowledge one had in professional development world)

Let’s go to (very) basic programming (… in Android)

Okay, I admit, I have some knowledge in programming. I know Function, Class and Member Variables. And I know how to create a Simple Hello World App Android App with one MainActivity (hey! … you could do that even without typing a single line of code.. Using Empty Activity template by Android Studio 😁)

To make it more fancier, I can change the Simple Hello World App to Simple Hello Dagger 2 App. Code as below (bold those I add on top of the template).

class MainActivity : AppCompatActivity() {

val info = Info()

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

text_view.text = info.text

}
}

class Info {
val text = "Hello Dagger 2"
}

Sorry, I make simple thing slightly harder that it need to by using a class to store my text. And I made a member variable name info to store it. This is important to explain the use of Dagger 2 later.

All very simple so far, I hope.

Moving Info out of Activity…

In real App, I am not likely to only have a single member variable info. There may be others. Or perhaps I would like to share the same info across multiple activities.

To make this better, instead of creating info in MainActivity class, I want my info (and all other member variables) to be created somewhere else and send in. Hey you know what? there’s a term for this… It is called Dependencies Injection 😉.

That sounds really simple… maybe I could do as below?

class MainActivity(val info:Info) : AppCompatActivity()

Ops!! Sorry, Android doesn’t allow me to simply add argument to it’s Activity’s constructor 🙁. If I want, I have to do the hard way. Refers to StackOverflow. Even if I don’t mind the hard way, this is also almost impossible, as this is the first Activity of my App, who will send it through?

If you have more experience in Android development, perhaps you could think of using the Application to help you… Spot on, you are right! … But I am the story teller here. I am here to talk about Dagger 2, let’s get back to the topic…

Based on a true story…

With that need, people starts imagining, how nice if we could magically have all dependencies injected (in my case, the dependency is info). For Android, the imagination gave birth to Dagger, by this group of most admirable experts, works for Square. Google admire their work so much, and make the second version of it, called Dagger 2.

It’s popularity is so great… until one day a dummy also like to learn about it… and decided to create a blog …. Okay, enough history…

Making Info appear magically?

With Dagger 2 created, one could now make Info magically appears. The most magically is to totally remove the line val info = Info(), but this is TOO magical. Beyond Dagger 2 capability, might need David Copperfield.

So to be more realistic, we still have to tell MainActivity to have info member variable, but DOES NOT need to create/initialize it (i.e. leave that to happen magically).

In Kotlin, because we want info as non-nullable item, hence it has to be initialized with something. But since we don’t know what it will initialized to, and waiting for the magic from Dagger 2, we will need to inform Kotlin to worry about that later by adding a lateinit modifier to it.

So in short, just add lateinit var info: Info to replace the previously removed line.

class MainActivity : AppCompatActivity() {

lateinit var info: Info
    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

text_view.text = info.text

}
}

class Info {
val text = "Hello Dagger 2"
}

Hey, don’t compile and run the above code, it will CRASH 💥!!! It is simply because info has not yet bee initialized.

Sorry no magic yet. Don’t get mad at me… This is not a trick. I promise we will not need to initialize it in MainActivity. We’ll let Dagger 2 to do it for you

Now, into the real Dagger 2 world…

Adding Dagger 2 libraries

But before that, some mundane stuff. Anything you need beyond basic Android stuff, you’ll have to manually add the libraries to your project. Dagger 2 is no different. Just follow the step below

In your app’s build.gradle file, (note: not project’s build.gradle), add the bold lines as following

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

And

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// ... other dependencies ...
implementation 'com.google.dagger:dagger:2.13'
kapt 'com.google.dagger:dagger-compiler:2.13'
}

Then sync your project. You now have Gun 2 with you… Ops, I mean Dagger 2.

Back to real code… Introducing @Component

Let’s get back to actual code. Now let me introduce you to a little thing call @Component. It’s a way for me to tell Dagger 2 , “Hey! I want a little magic box that does the magic instantiating my member variable”

I declare my magic box like this (as an interface)

@Component
interface MagicBox
I call it MagicBox just to make it different from other tutorial, so you know you could name it anything. Other tutorial will call it <Something>Component. In a group project I recommend follow this convention, so everyone could understand your code

I also need to tell my magic box, it is there to perform it’s magic on MainActivity. So to do that, I create a poke function accepting MainActivity in my MagicBox.

@Component
interface MagicBox {
fun poke(app: MainActivity)
}
Note I use poke just to make it different from other tutorial, so you know you could name it anything. Almost every other example I see, people call it inject. In a group project I recommend follow this convention, so everyone could understand your code.

Now, to make things a little clearer how they are related, you could imagine that MagicBox would be used to Poke MainActivity as diagram below, and provide the info to MainAcitivy. We just need to put info into the MagicBox, then the magic shows will be done! … I’ll show you how info is inserted into MagicBox in a short while…

Before showing how info is place in the MagicBox, let’s do some imagination here. This is in case you are wondering why the trouble of making MagicBox while we could just have info created directly in MainActivity.

Assuming we have a lot of other members variable other than info, and we also have other activities and classes that needs them. So the diagram will be as below, and the MagicBox handle all the poking happily, without any activities or classes worry about initiating their own member variables.

👏👏👏, MagicBox handles all these for us!! How nice…

Okay, let’s get back to reality of single info and one MainActivity, since we want to create the world’s simplest Android App with Dagger 2.

Putting `Info` into @Component… Intro to @Inject

Okay, now let’s put info into @Component. …

I guess you must be thinking if we have to manually put info into @Component, then what’s so special about @Component. Can’t we create a class to do just that? That’s no magic at all!!!

Wait … The Dagger 2 magic is coming soon… Soon I mean NOW.

The magic is, I don’t need to put info into MagicBox. All I need to do is add some special magic keyword (or better known as annotation) to my Info class, and Dagger 2 will be able to know where to get it.

Let me introduce to you…. Mr. @Inject!!

Change the little Info class from

class Info  {
val text = "Hello Dagger 2"
}

to

class Info @Inject constructor() {
val text = "Hello Dagger 2"
}
Sorry you need to add a little more than just @Inject, as we omit the constructor in the earlier code. Since the @Inject needs to be added on the constructor, we need to resurface the Kotlin constructor through the constructor() function above.

With the @Inject annotation in place, Dagger 2 would then smart enough to get the Info class instantiated as needed through the MagicBox. It’s so easy, that you could add @Inject to almost any existing class, and the class object would be hook up to the MagicBox magically for its creation as needed.

If you wonder how… That’s the magic Dagger 2 does under the hood. So let’s don’t worry about it, since we are just dummies 😝.

Building the MagicBox… Another Dagger 2’s magic

It is not all over yet. We have define the MagicBox, and also have easily hook up Info to our MagicBox. We also have a poke function in MagicBox that we could use to poke MainActivity.

Up till now, we haven’t poke it yet!!

Before we can do any poking, we need to Build the MagicBox

But MagicBox is an Interface. Who want to implement the detail of it?

Fear not!! That’s another magic from Dagger 2. Since you have name it MagicBox, all you need to do is acknowledge Dagger 2 is the Lord over the MagicBox by calling a new magically created Static Class name DaggerMagicBox.

This Static Class will provide you the Builder to build MagicBox. To build it you just need to call

DaggerMagicBox.create()
Don’t worry if Android Studio complaints they don’t recognize DaggerMagicBox, it is not created yet at that time. Just trust Lord Dagger 2, and he shall provide. Click Compile/Run… it will be as promised, magically created during compilation, and you will have it!!

Now you can poke

Okay, the poking of MainActivity could be done by adding the below code in bold. (i.e. create the magicBox, and call the poke function from there. Sending in MainActivity by using this)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMagicBox.create().poke(this)
text_view.text = info.text
}

Ideally after this step, all should work.

Compile… run… CRASH 💥!!! It complains the same thing, info is not initialized yet!!!

Please please, don’t shoot me… I didn’t lie on the magic of Dagger 2. Just allow me one more step below… promise last one…

@Inject again!!

In MainActivity, we have info defined as below

lateinit var info: Info

Dagger 2 doesn’t want to hijack any member variable by creating them without having my permission. This is good, as I might want to have my own Info sometimes.

So to inform Dagger 2 which member variable I want it to create magically, just use the same magic word i.e. @Inject, by putting in front of the member variable.

@Inject lateinit var info: Info

DONE!!! That’s all. Compile, works!!!

World’s simplest Android App with Dagger 2 code

With that, all the codes shared is as below, all in a file (less than 20 lines in total, and only 4 lines of Dagger 2 related codes in bold)

class MainActivity : AppCompatActivity() {

@Inject lateinit var info: Info

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMagicBox.create().poke(this)
text_view.text = info.text
}
}

class Info @Inject constructor() {
val text = "Hello Dagger 2"
}

@Component
interface MagicBox {
fun poke(app: MainActivity)
}

You can get the entire project from

My hope is the single page code would help one to easily link up all the essential pieces of working with Dagger 2.

Is this the end of show?

No, definitely not. This is just the tip of the iceberg of Dagger 2. But I think for a dummy like me, digesting this simple piece is a good start, and my brain need to rest a bit to continue.

I know what I shared is most basic (and I hear some of you complaint saying, this is injustice to Dagger 2. Sorry… I’ll catch up to that later if reader likes to hear more), and I purposely left out some other also important element such as @Module, @Singleton, @Scope etc. They are not here so I could minimize as much, make it more bearable to a total newbies. But they play important roles to make Dagger 2 of great use.

So I have written the next one as linked below if you like to continue reading.

Optionally, you could also search for other Tutorial, as I believe this one would have give you a good basic grasp of how things are connected. With it you might be ready to read the more solid tutorial from elsewhere.


I hope you appreciate this post and it’s helpful for you. Do share with others.

You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~