Open In App

Why to Use the Dependency Injection Framework like Dagger in Android?

Last Updated : 23 Dec, 2021
Improve
Improve
Like Article
Like
Save
Share
Report

In our project, we may or may not have used a dependency framework. In this blog, we will discuss why we need a dependency framework and why using one in our project is beneficial. We can assume that this is an interview question in this case. In this Geeks for Geeks article, we will respond to it by discussing the following topics:

  1. Why do we use a dependency injection framework in Android, such as Dagger?
  2. How do we give the framework our configuration?
  3. Conclusion

Note: This blog is not about learning Dagger or any dependency injection framework; however, it will help you understand how it can be useful for Android projects and you will be able to persuade anyone to use a Dependency Injection Framework based on the requirement.

Why do we use a dependency injection framework in Android, such as Dagger?

Consider that when we have to create a large number of objects that are dependent on a large number of other objects in our project, it becomes difficult as the project grows larger. With the code base growing, we may require some good external support to keep track of everything. That is one of the scenarios in which we employ a dependency framework. The other use-cases will be covered later in this blog. Let’s look at an example to better understand this use case. Consider the following scenario: we have two activities, Activity A and Activity B. Both require an object Downloader, which in turn requires the request. The request will now be dependent on Executor and HTTPClient.

Image #1: The Downloader Schematic Diagram

In this case, we first create an object of Executor and HttpClient and pass it to the request object, as shown below.

Kotlin




val somePostExec = postExec()
val somePostClient = httpClient()
val somePostReq = postReq(postExec, httpClient)


then this request which is sent is passed through like:

Kotlin




val myDownloader = Downloader(somePostReq)


This is how we can make a Downloader object. Consider that we will be using this in both activities (A and B), so we will need to write all four lines again and again. To avoid rewriting this code, we can create a factory class and create the Downloader using:

Kotlin




val myDownloader = GeeksDownloader.create()


where GeeksDownloader is:

Kotlin




object GeeksDownloader{
    fun create():Downloader{
        val someExec = someExecutor()
        val someClient = someClient()
        val someRequest = someRequest(executor, client)
        return Downloader(someRequest)
    }
}


Dependency Injection is based on the concept of Inversion of Control, which states that a class’s dependencies should come from outside. In other words, no class should instantiate another class; instead, instances should be obtained from a configuration class. Consider what would have happened if we had simply given some framework some configuration, such as 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 been simplified. We only needed to write some code to pass the configuration to the framework, and the framework would have generated the Factory classes for us. That’s what we’d have done.

A Scenario

Consider the following scenario: we are hosting a birthday party at our home and require a cake. So, making a cake on our own requires a lot of effort and precision. We can simply place an order with a bakery, which will act as the framework, taking our instructions and delivering the cake to us. We are the consumer in this case. Let’s look at how we can pass the configuration to the framework now.

How do we give the framework our configuration?

Using a framework reduces the amount of code we write. So, in general, we give the framework configuration such as how to create the object, the scope (lifecycle) of the object so that the framework can create dependencies for us, and then consumers can get the dependencies based on the configuration we provided.

Now, consider the Dagger framework as an example.

Dagger is based on annotation processing, which generates code for us. Dagger only needs the configuration that we provide by creating some classes and interfaces and using annotations. @Module-annotated classes are responsible for providing objects that can be injected. These classes define methods that are annotated with @Provides. The objects returned by these methods can be used for dependency injection. The @Inject annotation is used to specify a dependency within a consumer.

When an interface is annotated with @Component, Dagger uses it to generate the corresponding component class, which acts as a bridge between the module (provider of the objects) and the consumer to provide the required dependencies. It obtains the necessary dependency from the module class. Creating an object with the application scope (application lifecycle) or activity scope (activity lifecycle) also becomes simple. There are numerous other ways in which the framework can assist us. Dagger only requires us to provide the configuration for the required dependency, and it handles the rest by generating the code internally using the annotation we provided.

Conclusion

We should use the dependency framework for the following reasons:

  1. It facilitates the management of complex dependencies.
  2. It simplifies unit testing by allowing us to pass all external dependencies so that we can easily use mocked objects.
  3. It easily manages the object’s scope (lifecycle).
  4. This is why we need to use a Dependency Injection Framework in Android, such as Dagger.


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads