Android — Clean architecture with Dynamic-features and Hilt/Dagger2 (Pt.3)
--
Introduction
As you noticed by the title, this is the third part of the series of articles explaining and describing my process of creating an application using dynamic features with Hilt/Dagger. You may find the previous posts here:
Hilt / Dagger
The proper setup to use Hilt in your application is well-described on Google’s webpage, but I’ll quickly show an example based on the code I implemented.
In order to use Hilt, we must annotate our Application class with @HiltAndroidApp.
If we are going to manage dependency injection on our app module, we can still use Hilt by adding the @AndroidEntryPoint on one of the following Android components:
Application
(by using@HiltAndroidApp
)ViewModel
(by using@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
To exemplify, we are going to inject an instance of a “ColorProvider” inside our view model.
First, we need to annotate the activity and fragment holding this fragment with the @AndroidEntryPoint
With that done, we are now able to inject our “ColorProvider” inside our view model by using a binding injection on our constructor
Great, that’s enough to have our dependency injection working on our app module, but what about our dynamic features?
Dagger2
Well, Hilt is not supported yet on dynamic features, and the workaround is to use Dagger2 instead, and now here comes the trick. Hilt provides an annotation to help with that called @EntryPoint, so we must declare an interface in our app module annotated with this and provide the function signatures of the dependencies that will be used by our dynamic features. In our example, the only dependency that is being used by the other modules is Retrofit.
The dependencies declared must be installed in a defined scope by using the @InstallIn annotation, which in our case is defined into SingletonComponent
Feature module
Now, in our feature module, we must create a component that depends on the DaggerDependencies interface we created and also add all the needed Dagger modules.
In order to make our dependencies work, we must define an inject function that receives as a parameter the target class to inject the dependencies, which will be in our case our fragment.
For those who already worked with Dagger and multi-modules, this is not new, the only difference is the appDependencies function defined inside the Builder, which is the key to connect our dependencies.
Right after declaring the component and rebuild your project, you will be able to locate the generated Dagger component that will be named “DaggerPoolsComponent”
Do you remember the appDependencies function we defined in our component? It is time for it to shine. We must call this function and pass the EntryPoint we defined using the “EntryPointAccessors”.
Note: I defined the inject function using extension functions to reduce the amount of code inside my fragment, but it could be defined inside the fragment without any problems.
Now the only thing we must do to fulfill our mission is to call the inject function, and according to Google’s documentation, we must do it inside the onAttach function.
When using activities, inject Dagger in the activity’s
onCreate()
method before callingsuper.onCreate()
to avoid issues with fragment restoration. During the restore phase insuper.onCreate()
, an activity attaches fragments that might want to access activity bindings.When using fragments, inject Dagger in the fragment’s
onAttach()
method. In this case, it can be done before or after callingsuper.onAttach()
.
We now have finished the setup to use dynamic-features along with Hilt/Dagger.
Congratulations and thanks for accompanying me on that journey!!! 🎉
Any thoughts ideas or suggestions, please add some comments.