Why do we use the Dependency Injection Framework like Dagger in Android?

We might or might not have used a dependency framework in our project. In this blog, we are going to discuss why we need a dependency framework and why it is useful to use one in our project.

Here, we can assume that this is an interview question.

Question: "Why do we use the Dependency Injection Framework like Dagger in Android?"

In this blog, we are going to answer it by covering the following:

  • Why do we use a dependency injection framework like a Dagger in Android?
  • How can we give our configuration to the framework?
  • Conclusion

Note: This blog is not about learning Dagger or any dependency injection framework, but, this will help you in understanding how it can be useful for Android Project and you will be able to convince anyone to use a Dependency Injection Framework based on the requirement.

Let's get started.

Why do we use a dependency injection framework like a Dagger in Android?

Consider, that when we have to create a lot of objects which are dependent on many other objects in our project, it becomes tough when the project becomes bigger. With the code base increasing, we might need some good external support to manage it all. That is one of the use-cases for that we use a dependency framework. We will learn about the other use-cases later in this blog. Let's understand this use-case with an example.

Consider an example we have two activities, Activity A and Activity B. Both require an object Downloader, in which Downloader will require the request. Now, the request will depend upon Executor and HTTPClient.

Here, we first create an object of Executor and HttpClient and we pass them to request object like,

val executor = Executor()
val client = HttpClient()
val request = Request(executor, client)

then we pass request in Downloader,

val downloader = Downloader(request)

This is how we can create an object for Downloader. Now, consider that we need to use this in both activities(A and B), we need to write all these 4 lines again and again.

To reduce writing this code, again and again, we can create a factory class and create the Downloader using,

val downloader = DownloaderFactory.create()

where DowloaderFactory is,

object DownloaderFactory{
    fun create():Downloader{
        val executor = Executor()
        val client = HttpClient()
        val request = Request(executor, client)
        return Downloader(request)
    }
}

This will make the task easy.

Dependency Injection in build upon the concept of Inversion of Control which says that a class should get its dependencies from outside. In simple words, no class should instantiate another class but should get the instances from a configuration class.

Now, consider, what if we would have just provided some sort of configuration to some framework like the way to create the object, scope(lifecycle), and that framework would have created these types of Factory classes for us. Our task would have become easy. We just had to write some code to provide the configuration to the framework, and the framework would have created the Factory classes for us. We would have just used that.

For example, consider we have a birthday party at our place and we need a cake. So, to make a cake on our own takes a lot of effort and perfection. We can just place an order to a bakery, which will act as the framework which will take instructions from us and then deliver the cake to us. Here, we are the consumer.

Now, let's see how we can give the configuration to the framework.

How can we give our configuration to the framework?

Using a framework reduces a lot of code written by us. So, in the generic term, we give configuration to the framework like the way to create the object, scope(lifecycle) of the object so that the framework can create dependencies for us, and then consumers can get the dependencies based on a configuration which we had provided.

Now, let's consider the example for Dagger framework here,

Dagger work on the basis of annotation processing which generates the code for us. Dagger just requires the configuration from us that we provide by creating some classes and interfaces and using annotations along with it.

For that, we use majorly four annotations,

@Module, @Provides, @Component, and @Inject.

Classes annotated with @Module are responsible for providing objects which can be injected. Such classes define methods annotated with @Provides. The returned objects from these methods are available for dependency injection.

@Inject annotation is used to define a dependency inside the consumer.

@Component is annotated to an interface, Dagger uses @Component and generates the corresponding component class for that which works as a bridge between the module(provider of the objects) and consumer to provide the required dependencies. It takes the required dependency from the module class.

Also, things like creating an object with the application scope(application lifecycle) or activity scope(activity lifecycle) become easy. There are many other things with which the framework can help us.

If you want to learn about the Dagger in detail, refer to this blog.

Dagger just requires us to give the configuration for the required dependency and rest it takes care of using the annotation we have provided by generating the code internally.

Conclusion

We should use the dependency framework because of the following:

  • It helps us in managing the complex dependencies easily.
  • It makes the unit testing easy by enabling us to pass all the dependencies from outside so that we can easily use the mocked objects.
  • It easily manages the scope(lifecycle) of the object.

This is why we need to use Dependency Injection Framework like Dagger in Android.

Happy learning.

Team MindOrks :)

Also, Let’s connect on Twitter, Linkedin, Github, and Facebook