Issue
I have an Android project with Hilt dependency injection. I have defined MyApplication
and MyModule
as follows.
@HiltAndroidApp
class MyApplication : Application()
@Module
@InstallIn(ApplicationComponent::class)
abstract class MyModule {
@Binds
@Singleton
abstract fun bindMyRepository(
myRepositoryImpl: MyRepositoryImpl
): MyRepository
}
MyRepositoryImpl
implements the MyRepository
interface:
interface MyRepository {
fun doSomething(): String
}
class MyRepositoryImpl
@Inject
constructor(
) : MyRepository {
override fun doSomething() = ""
}
I can now inject this implementation of MyRepository
into a ViewModel:
class MyActivityViewModel
@ViewModelInject
constructor(
private val myRepository: MyRepository,
) : ViewModel() { }
This works as expected. However, if I try to inject the repository into a service, I get an error java.lang.Class<MyService> has no zero argument constructor
:
class MyService
@Inject
constructor(
private val myRepository: MyRepository,
): Service() { }
The same error occurs with an activity, too:
class MyActivity
@Inject
constructor(
private val myRepository: MyRepository,
) : AppCompatActivity(R.layout.my_layout) { }
What am I doing wrong with the injection?
Solution
From the documentation on how we Inject dependencies into Android classes, we can learn the following:
Hilt can provide dependencies to other Android classes that have the @AndroidEntryPoint annotation.
Hilt currently supports the following Android classes:
Application
(by using@HiltAndroidApp
)ViewModel
(by using@HiltViewModel
)Activity
Fragment
View
Service
BroadcastReceiver
So when you subclass any of these Android classes, you don't ask Hilt to inject dependencies through the constructors. Instead, you annotate it with @AndroidEntryPoint
, and ask Hilt to inject its dependencies by annotating the property with @Inject
:
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject
lateinit var mAdapter: SomeAdapter
...
}
So, in your case you should inject MyRepository
in MyActivity
and MyService
like this:
@AndroidEntryPoint
class MyService: Service() {
@Inject
lateinit var myRepository: MyRepository
...
}
@AndroidEntryPoint
class MyActivity: AppCompatActivity(R.layout.my_layout) {
@Inject
lateinit var myRepository: MyRepository
...
}
And remember:
Fields injected by Hilt cannot be private
That's it for Android classes that is supported by Hilt.
If you wonder what about classes not supported by Hilt (ex: ContentProvider
)?! I recommend learning how from this tutorial @EntryPoint annotation on codelab (also don't forget to check the documentation for how to Inject dependencies in classes not supported by Hilt).
Answered By - Ahmed Shendy
Answer Checked By - Mildred Charles (JavaFixing Admin)