Assisted Injection with Hilt in Android allows us to handle scenarios where some dependencies are known at compile-time, while others are determined at runtime. By using Assisted Injection, we can leverage the power of Hilt to provide the necessary dependencies when creating instances of our classes. In this article, we will explore how to use Assisted Injection with Hilt using two examples: one involving a custom class and another involving the injection of WorkManager in an Android application. Let’s dive into the details!
Let’s say we have a class having 3 parameters and Hilt knows how to inject two of them but the third parameter’s value is decided at runtime. How can we use Hilt in such cases?
Use Assisted Injection in custom class
Hilt allows us to do this using Assisted Injection. Let’s go through it using an example of a BlogUtil class which needs 3 params namely: context, firebaseUtils and blogPost.
Hilt allows us to do this using Assisted Injection. Let’s go through it using an example of a BlogUtil class which needs 3 params namely: context, firebaseUtils and blogPost.
Step 1: Create a class using Assisted Injection
class BlogUtil @AssistedInject constructor(
@ActivityContext val context: Context,
firebaseUtils: FirebaseUtils,
@Assisted
val blogPost: BlogPost
){
...
}
class FirebaseUtils @Inject constructor(){
...
}
Differences here from normal Injection
- We use @AssistedInject instead of @Inject for constructor injection.
- Arguments which need to be provided at runtime are annotated with @Assisted.
Step 2: Create a factory for class created in Step 1
Even after using @AssistedInject, we can’t directly inject BlogUtil in our fragment, we need to create a factory first.
@AssistedFactory
interface BlogUtilFactory {
fun create(blogPost: BlogPost): BlogUtil
}
Points to note for our factory
- We create a Factory for our class as an interface.
- Annotate our factory with @AssistedFactory. This annotation tells the system that this interface is used to create an instance of a class which requires Assisted Injection.
- Create a fun which return an instance of our class and accepts only those parameters which are to be provided at runtime that means arguments annotated as @Assisted in our BlogUtils class.
Step 3: Using our class in a component
Now when we want to use BlogUtil class in our component (in our example, fragment), we will inject it’s factory instead of the class itself and then use the factory to create an instance of the actual class.
@AndroidEntryPoint
class BlogFragment : BaseFragment{
@Inject
lateinit var blogUtilFactory: blogUtilFactory
private var blogPost: BlogPost
private lateinit var blogUtil: BlogUtil
....
fun getBlogUtil(){
blogUtil = blogUtilFactory.create(blogPost)
}
}
Points to note here
- We inject our BlogUtilFactory using field injection
- We create a fun which creates an instance of BlogUtil class using BlogUtilFactory create fun.
Voila!!! We are good to go. We can now use blogUtils in our fragment.
Now when we know what is Assisted Injection and how to use it, let’s see an example, where Android forces us to use Assisted Injection, injecting Work Manager.
Inject WorkManager using Hilt
Step 1: Include Dependencies
To use Hilt in WorkManager, first we have to include a Hilt worker dependency and an annotation processor that works on top of the Hilt annotation processor.
dependencies {
implementation("androidx.hilt:hilt-work:1.0.0")
// When using Kotlin.
kapt("androidx.hilt:hilt-compiler:1.0.0")
// When using Java.
annotationProcessor("androidx.hilt:hilt-compiler:1.0.0")
}
Step 2: Use Assisted Injection in Worker class
@HiltWorker
class NotificationWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
workerDependency: WorkerDependency
) : Worker(appContext, workerParams) { ... }
- Annotate the Worker class with @HiltWorker
- Use @AssistedInject for constructor injection
- Context and WorkerParameters must be annotated with @Assisted.
Note: We can only use Application scoped bindings (bindings annotated with @Singleton) or unscoped bindings in Worker objects.
Step 3: Implement Configuration.Provider interface in Application class
@HiltAndroidApp
class MyApplication : Application(), Configuration.Provider {
@Inject lateinit var workerFactory: HiltWorkerFactory
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}
Note: Because this customizes the WorkManager configuration, we must remove the default initializer from the AndroidManifest.xml file as specified in the WorkManager docs. To do so, we have to add the following code in our Manifest file.
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
That’s it for this article. Hope it was helpful! If you like it, please hit like. Don’t forget to visit the provided links to other articles in the series and show your appreciation.
Thanks for reading!!.
Checkout the other articles of the Dependency Injection series:
