Dependency injection will significantly improve your code. It makes your code more modular, flexible and testable. Actually its name sounds more complicated than the idea which stands behind it.
In this part of the series we are going to learn about dependency injection. We will then implement it in “Kriptofolio” (previously “My Crypto Coins”) app. We are going to use Dagger 2. Dagger 2 is the most popular open-source dependency injection framework for Android. This is a valuable skill to have for creating modern apps, even thought the learning curve is hard enough.
- Introduction: A roadmap to build a modern Android app in 2018–2019
- Part 1: An introduction to the SOLID principles
- Part 2: How to start building your Android app: creating Mockups, UI, XML layouts
- Part 3: All about that Architecture: exploring different architecture patterns and how to use them in your app
- Part 4: How to implement Dependency Injection in your app with Dagger 2 (you’re here)
- Part 5: Handle RESTful Web Services using Retrofit, OkHttp, Gson, Glide and Coroutines
What is Dependency Injection?
To explain dependency injection first we have to understand what dependency means in programming. A dependency is when one of the objects depends on the concrete implementation of another object. You can identify a dependency in your code whenever you instantiate an object within another. Let’s take a look at a practical example.
As you see from this example your class
MyAppClass will depend directly on concrete configuration and implementation of your library class
MyLibrary. What if you would like one day to use a third-party library instead? What if you would like to have another class where you would like to use exactly the same library configuration? Every time you will have to search through your code, find exact place and change it. It’s just a few examples.
The idea is that this tight coupling between the components of the application will make your development work harder as your project grows. To avoid any problems, let’s use dependency injection for loosening the coupling described.
That’s it, that’s a very primitive dependency injection example. Instead of creating and configuring a new
MyLibrary class object inside your class
MyAppClass, you just pass or inject it into the constructor. So
MyAppClass can be totally irresponsible for
What is Dagger 2?
Dagger is a fully static, compile-time, open-source dependency injection framework for both Java and Android. In this article I will be talking about its second version which Google maintains. Square created its earlier version.
Dagger 2 is considered to be one of the most efficient dependency injection frameworks built to date. Actually if you compare Dagger 1, Dagger 2 and Dagger 2.10 you would discover each implementation is different. You need to relearn it each time as there were significant changes done by the authors. When writing this article I am using Dagger 2.16 version and we are going to focus only on it.
As you now understand about dependency injection, our classes should not create or have dependencies. Instead they need to get everything from outside. So when using Dagger 2, this framework will provide all the dependencies needed.
It does this by generating a lot of boilerplate code for us. That generated code will be fully traceable and will mimic the code which a user may write by hand. Dagger 2 is written in Java and the code generated by its annotation processor will be Java code too.
However it works with Kotlin without any problems or modifications. Remember that Kotlin is fully interoperable with Java. If compared to similar frameworks, Dagger 2 is a less dynamic one. It works at compile time rather than at run-time with reflection. There is no reflection usage at all. All that means is that this framework will be harder to set up and to learn. It will provide performance boost with compile-time safety.
Manual Dependency Injection without tools
You may have noticed in the My Crypto Coins app source code from the previous part that there is a piece of code for injecting objects without using any dependency injection tools. It works fine, and this solution would be good enough for such a small app like this. Take a look at the utilities package:
As you see this class will do all the work. It will create ViewModel factories for activities or fragments that require them.
Then you use
InjectorUtils class like this where you need to get a specific ViewModel factory:
As you see our
MainListFragment class don’t even know about
AppDatabase. It gets a successfully constructed factory from InjectorUtils class. Actually this is one simple way to do it. We are going to get rid of it and learn how to setup Dagger 2 tool for advanced dependency injection. If this app would expand in functionality and code, I don’t doubt we would start seeing benefits really fast of using a professional dependency injection framework over a manual solution.
So let’s delete
InjectorUtils class right now and learn how to setup Dagger 2 in My Crypto Coins app source code.
Dependency Injection for MVVM with Kotlin
How to setup Dagger 2 with ViewModels, Activities and Fragments
Now we’ll go through the Dagger 2 step by step setup on the My Crypto Coins app project.
To begin, you should enable Kotlin’s own Annotation Processing Tool (kapt). Then add special Dagger 2 dependencies.
You can do this by adding these lines to your gradle file:
Kapt plugin will enable the compiler to generate stub classes required for interoperability between Java and Kotlin. For convenience we will define the concrete Dagger 2 version in a separate gradle file, as we do that with all our dependencies.
To find the latest version available check the releases at Dagger 2's official repository on Github.
Now, create your application
Skip this if you already have this class set. After you’ve done that, we will leave it as it is for a while, but come back later.
For My Crypto Coins app, we already have created the application class earlier.
Next, update your manifest file to enable your
Skip this if you have already done that before.
For My Crypto Coins app, we’ve also already set the
App class in the manifest earlier.
Now let’s create a new package called
Here we are going to keep all the files related to Dagger implementation.
AppModule class module which will provide dependencies all over your application.
As you see, to create a Dagger module we need to annotate it with the special
@Module annotation. Projects usually have multiple Dagger modules. It is typical for one of them to provide app-wide dependencies. This
AppModule will be used to initialize objects used across our application, such as Room database, Retrofit, Shared Preference, etc.
As an example, we could discuss a very common scenario for AppModule to provide a Context object in case we need it to get access to it anywhere in our app. Let’s analyze the code to see how to do that.
We need to use a special Dagger annotation
@Provides. It tells Dagger that the method provides a specific type of dependency, in our case, a Context object. So when somewhere in the app we request to inject a Context, AppModule is the place where Dagger finds it. And it does not matter the names of our methods, as Dagger cares only about the return type. It is only common practice to name the method with provide prefix, but it can be anything you want.
@Singleton annotation which you see applied to the same method is not part of the Dagger annotations. It is contained inside the javax package. This annotation tells Dagger that there should only be a single instance of that dependency.
You don’t need to write the boilerplate code to check if another instance of the object is already available. When generating the code Dagger will handle all that logic for you because of this annotation. Notice that our AppModule includes another module ViewModelsModule. Let’s create it now.
ViewModelsModule class module. This module will be responsible for providing ViewModels all over your application.
This module uses Dagger 2 feature map multi bindings. Using it, we contribute objects of our choosing into a map that becomes injectable anywhere in our app. Using the combination of Dagger annotations
@IntoMap and our custom annotation
@ViewModelKey(this one we are going to create), we create an entry inside our map with key
MainViewModel::class and value
MainViewModel instance. We bind specific factory with the help of some common
ViewModelFactory class. We need to create this class.
Create a custom annotation class
This class is used for binding ViewModels in the
ViewModelsModule. The specific annotation
@ViewModelKey represents the key of our map. Our key can be only a class that inherits from
ViewModelFactory is a utility class which helps you dynamically create ViewModels. Here you provide the generated map as an argument. The
create() method will be able to pick the right instance from the map.
ActivityBuildersModule class module.
This module is responsible for constructing all your activities. It will generate
AndroidInjector for all Activities defined in this class. Then objects can be injected into activities using
AndroidInjection.inject(this) in the
onCreate function from the activity lifecycle. Notice that this module also uses another separate module responsible for fragments. We will create this module next.
MainListFragmetBuildersModule class module.
This module will build all your fragments related to
MainActivity. It will generate
AndroidInjector for all Fragments defined in this class. Objects can be injected into Fragments using
AndroidSupportInjection.inject(this) in the
onAttach function from the fragment lifecycle.
AppComponent interface component.
Component is a very important interface. It will enable all the above to start working together. It does this by connecting objects to their dependencies. Dagger will use this interface to generate the code necessary to perform the dependency injection.
To create a component class you will need to use Dagger annotation
@Component. It takes a list of modules as an input. Another annotation
@Component.Builder allows us to bind some instance to component.
Then generate a graph object.
At this moment you have all your modules and your component setup. You can generate your graph object by selecting Build -> Make Module inside your Android Studio IDE. We will need this generation for future steps.
Now create an
This will also be needed for future steps.
Injectable interface should be implemented by activities or fragments which we want to be injectable automatically.
Create a new helper class named
It is just a simple helper class to avoid calling the inject method on each activity or fragment.
Next, setup the
App class which we already created before.
Because the application has activities, we need to implement the
HasActivityInjector interface. If you see an error called out by Android Studio on
DaggerAppComponent, it is because you have not generated a new file, as was pointed out in the previous step.
MainActivity to inject the main ViewModel factory and add a support for fragment injections.
Because our activities have child fragments we need to implement
HasSupportFragmentInjector interface. We also need this because we plan to make injections into our fragments. Our activity should not know about how it is injected. We use the
AndroidInjection.inject(this) code line inside overriding
inject() method will cause Dagger 2 to locate the singletons in the dependency graph to try to find a matching return type. However we don’t need to write any code here because it’s done for us by previously created
AppInjector helper class which we initialized inside our application class.
MainListFragment to inject the main ViewModel factory.
Similar to activities, if we want our fragment to be injectable, then into its
onAttach method we should write the code
AndroidSupportInjection.inject(this). But again this is a job done by the
AppInjector helper, so we can skip that. Just notice that we need to add the
Injectable interface which we created earlier for the helper to work.
Congratulations, we’ve implemented Dagger 2 in the My Crypto Coins app project. Of course this article is a quick guide to deploy Dagger 2 in your app straight away, but not deep coverage of it. I recommend that you continue researching this topic if you feel lost on the basics.
Check out the source code of the updated “Kriptofolio” (previously “My Crypto Coins”) app on GitHub.
Ačiū! Thanks for reading! I originally published this post for my personal blog www.baruckis.com on October 7, 2018.