Dependency Injection Overview in Android.

Joseph James (JJ)
6 min readJul 12, 2020

--

Introduction

Hey Folks, In this blog I am explaining the concept of dependency injection in Android perspective, So the first question that I have is what is this “Dependency Injection”, Let’s see what Wikipedia definition of the same

In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. In the typical “using” relationship the receiving object is called a client and the passed (that is, “injected”) object is called a service. The code that passes the service to the client can be many kinds of things and is called the injector. Instead of the client specifying which service it will use, the injector tells the client what service to use. The “injection” refers to the passing of dependency (a service) into the object (a client) that would use it.

Pretty Decent..ha, okay Let me try to explain the same a bit easier way, but before that, we should take a look at what Dependency management is…

What is Dependency Management

Dependency management as the name implies it has to parts, “Dependency” — “Management”,
Lets now switch into android, We all use the new MVVM design pattern for better Lifecycle management, say in your project you have a class named MainViewModel.java, and two other classes are consumed by our view model class (1) DataBaseService and (2) Network Service. For our view model to function we need these two classes, so in a broader sense when the ViewModel object has created the objects for (1) and (2) are also created. ..now that being said… you have seen a glimpse of what dependency is. Here the classes (1) and (2) are dependencies…And why is that?… Because the class MainViewModel needs these two classes to function.

Now we have an Idea about what dependency is, let’s move onto the hard part “Management,

The management covers 3 main things:

  • Where the dependencies are created.
  • Where the dependencies are passed.
  • How the dependencies are passed.

… but wait why do we need to manage the dependencies?, for that we need to understand what are the ways in which we can create the classes (1), (2) and then pass it to the ViewModel class.

Let’s consider the structure of our Android project.

Here the API key, DB name and Version are also dependencies.

Design Approach 1

Let’s consider that in our first approach we create the object of ViewModel class in the OnCreate function of out Activity. Because of this in the ViewModel constructor will create the new instances for (1) and (2), and when creating the object of (1) we initialize the DBname and Version in its constructor(Hardcoded), and when creating the object of (2) we initialize API key in its constructor(Hardcoded)…. So far so good.

But what are the problems associated with this design..?

  • Configurability, say if we need to change the database name, we need to go into the database service constructor and change it ie. we are not able to change the database name from outside. Consider that we have an SDK integrated into our Application, and both SDK and APP use database service and let’s say both SDK and APP use different DB names and versions. Will this work..? No, as the values in the constructor are hardcoded and for this, to work we should have a new class for database service and that will contribute to the reusability issue.
  • Objects are Expensive, The database service and network service are pretty expensive, so it is a Bad Idea to create the same object over and over when the activity is launched..why? As these classes are expensive it will waist the garbage collection cycles and app heap space.
  • This approach will make it difficult to write tests :)

Design Approach 2

In the approach above we have considered a top-down approach, now let’s consider a bottom-up approach. By bottom-up approach what I meant was Dependencies will be created even before creating the consumer classes. Let’s explain Bottom-Up in terms of our architecture. The first components that are created will be Api-Key, Database name and Database Version. Then with the help of these 3 classes, we create the Database Service(1) and Network service(2). And then (1) and (2) will be supplied to the view model(3) and then (3) will be supplied to The activity class. If we take a close look, the actual difference between the approaches (1) and (2) is that the flow of dependencies are reversed. Now this is called INVERSION OF CONTROL that’s just a fancy word, what I was trying to explain was that “ The Dependencies shouldn’t be created by the classes that use them, Instead they should be created and supplied from outside” This is the golden rule to improve the configurability of our codebase.

I will just give an example of the configurability thing. Suppose our Application consists of an SDK that uses the same network service, in the sense that our application and SDK uses different API key, so if we follow the Design approach 2, we pretty much have to do nothing but supply the SDK’s API key.

Now the next question arises, Where do we create these classes? now that is a very important questions, because creating the DB service and Network service every time is a painful process,

So if we are initiating the process of object creation in the Activity perspective, we are going to end up creating DB/Network services every time a new activity pops up. So the DB/Network services should only be created once and only once in an application cycle, ie. The scope of both the services will be that of the Application class. So whenever the application class object is created(Singleton) both our services will be created. But what if I need to create dependencies like Recycler view’s adapter, Linear Layout manager..etc…. Then we should use Activity/Fragment Scope for creating the dependencies.

What we have just seen are the 2 layers of dependencies..ie. Application Layer dependencies and Presentation layer Dependencies.

Application Layer -> DB service/Network Service

Presentation Layer -> Adapters/Layout Managers...etc.

Spoiler Alert: “ Scope and Layers of dependencies are the only two concepts that are needed to learn any Dependency Injection Framework”

And how do we supply all these dependencies, for that we can make our own classes, but… better libraries are available, my personal choice is Dagger2.

Now, this is something unimportant… The reason why I choose dagger2 was because

For Dependency management first, we had the JAVA BEANS, This used XML which made it very hard to do reconfiguration( this was mainly used in servlets), to overcome this Google came up with a DI framework named Guice, it didn’t use XML..instead it used Java Reflection,

The problem with juice was that It created a lot of classes/subclasses which made it hard for the developer to read the stack trace whenever a crash occurs. To solve this problem Square came up with Dagger1 which only used reflection for instance creation, for everything else it was using Annotation(Similar to reflection, but it is done at compile time), now for this there is a chance that Dagger1 can crash because the instance creation code was done at Runtime. Google made improvements to Dagger1… They completely got rid of runtime Reflection.ie They came up with a framework with DI working at Build time and named it Dagger2…which is by far the best framework for android According to me.

Conclusion

And that, Folks, is the essence of DI. If you are planning to implement a DI framework in your project, you should do that at the beginning… or else this can lead to a complete code refactoring :)

you can refer to this link to learn about dagger https://dagger.dev

--

--

Joseph James (JJ)
Joseph James (JJ)

No responses yet