Dependency Injection on Android with Dagger 2 (and Kotlin) — Part 2
In the first part of the series, we talked about the dagger annotations and how they are useful in our projects.
In the second part we will look at how we can use Dagger 2 to provide dependencies in our mobile apps.
Add following lines to app build.gradle
file
- The plugin kotlin-kapt (Kotlin Annotation Processor) is required for processing the kotlin annotations.
- The first dependency is from dagger required for annotations and other internal functionalities.
- The second dependency is our dagger compiler, which is required to process our dagger based annotations and generate the code.
- The third dependency is for Dagger android annotations.
- The fourth dependency is our dagger android annotation processor.
- The fifth dependency is optional, and it is required when we are working with
Support Fragments
.
For Android, the way we provide or create the object graph remain similar. What we improve on is how we inject the requested dependencies.
Injecting Dependencies
Android dependencies in activities and other framework classes are provided mostly using subcomponents.
Now, as we saw with our pure Kotlin examples in Part 1 we may easily create our component class and request a computer instance in our activities in following steps.
Let’s create an application class and instantiate our component inside it.
Now we can use this computerComponent
in our Activity and inject the dependencies as —
But there is a small issue here, A class should never know how it is being injected, But here our Activity manages the injection, which is not so bad, but not so good either.
And so there is a better approach to this —
Android Annotations
@ContributesAndroidInjector
- This is the easiest way of injecting dependency in our Activity.
- It is good to have custom scope for our provider function annotated with this
@ContributesAndroidInjector
for performance benefits discussed earlier.
Injecting Activities
Let’s take another example of injecting an activity ex.HomeActivity
with HomeViewModel
.
Given we have,HomeViewModel
with a constructor with @Inject
annotation to request the additional dependencies required to create it’s instance.
We declare the activity binding using the annotation @ContributesAndroidInjector
inside our ActivityBindings
module.
Notice the provider is annotated with @ActivityScope
custom scope.
Next we declare our application class as
Our application class needs to implement the HasActivityInjector
interface and provide a DispatchingAndroidInjector<Activity>
for injecting dependencies inside our Activity.
The DispatchingAndroidInjector
is again injected magically using Dagger.
We request dependencies in our Activity as
- The activity has to call
AndroidInjection.inject(this)
before the call tosuper
so that dependencies are initialised before fragment attachments. - In the above code block our HomeActivity requests
HomeViewModel
to be injected.AndroidInjection.inject(this)
requests the injectable dependencies from theApplication
class, which in turn usingDispatchingAndroidInjector
binds our dependencies to our activity.
Injecting Fragments
In a similar way we can also inject fragments with our dependencies in following steps.
Our activity hosting the fragment has to implement the HasFragmentInjector
and provide an instance of DispatchingAndroidInjector<Fragment>
In our fragment, we request the dependency in the onAttach
function.
Declaring activity subcomponents to provide dependencies
If you have a complex set of dependencies, the other way to provide dependencies is using subcomponents for our activities/fragments. I won’t go in much detail of that. Although you may read more about it here.
Sample Project
Issues faced
Dagger code was not being generated
- I was using annotationProcessor in place of `kapt`
- One of my projects was failing due to a missing import and the IDE wasn’t showing an error.
- I had a cyclic dependency.
NPE exception while using Android Injector
The android annotation processor was missing
Tips
- You shouldn’t instantiate objects in your classes rather pass them as dependencies.
- If the IDE isn’t working for you, Try using the command-line.
- Objects which request dependencies; can be easily tested using mocking. It is good to limit our constructor arguments to mockable types.
There is a lot more in Dagger 2 ex. Multibindings, Lazy injections, Provider injections etc. which we will leave for reader exploration :)
Follow the gist for the reference sources.
That’s all folks.