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?
Also If you overriding onCreate in your Service - don't forget to add super.onCreate() otherwise you will get runtime exception that the myRepository value cannot be initialised (I was struggling with this error for some time during refactoring my service so maybe it will be helpful for somebody)
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
override fun onCreate() {
super.onCreate()
}
}
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).
Your use of @Inject
on the MyService
class is as if MyService
is to be injected at some other location.
If I understand correctly, you want something more akin to:
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With