使用 Hilt 将存储库注入 Android 中的服务
Injecting a repository into a Service in Android using Hilt
我有一个带有 Hilt 依赖项注入的 Android 项目。我定义了 MyApplication
和 MyModule
如下。
@HiltAndroidApp
class MyApplication : Application()
@Module
@InstallIn(ApplicationComponent::class)
abstract class MyModule {
@Binds
@Singleton
abstract fun bindMyRepository(
myRepositoryImpl: MyRepositoryImpl
): MyRepository
}
MyRepositoryImpl
实现了 MyRepository
接口:
interface MyRepository {
fun doSomething(): String
}
class MyRepositoryImpl
@Inject
constructor(
) : MyRepository {
override fun doSomething() = ""
}
我现在可以将 MyRepository
的这个实现注入到 ViewModel 中:
class MyActivityViewModel
@ViewModelInject
constructor(
private val myRepository: MyRepository,
) : ViewModel() { }
这按预期工作。但是,如果我尝试将存储库注入服务,则会收到错误 java.lang.Class<MyService> has no zero argument constructor
:
class MyService
@Inject
constructor(
private val myRepository: MyRepository,
): Service() { }
activity 也会出现同样的错误:
class MyActivity
@Inject
constructor(
private val myRepository: MyRepository,
) : AppCompatActivity(R.layout.my_layout) { }
我注射有什么问题?
您在 MyService
class 上使用 @Inject
就好像 MyService
是在其他位置注入的。
如果我没理解错的话,你想要更类似于:
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
}
从关于我们如何 Inject dependencies into Android classes 的文档中,我们可以了解到以下内容:
Hilt can provide dependencies to other Android classes that have the @AndroidEntryPoint annotation.
Hilt currently supports the following Android classes:
Application
(by using @HiltAndroidApp
)
Activity
Fragment
View
Service
BroadcastReceiver
因此,当您对这些 Android 类 中的任何一个进行子类化时,您不会要求 Hilt 通过构造函数注入依赖项。相反,您使用 @AndroidEntryPoint
注释它,并要求 Hilt 通过使用 @Inject
:
注释 属性 来注入其依赖项
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject
lateinit var mAdapter: SomeAdapter
...
}
因此,在您的情况下,您应该像这样在 MyActivity
和 MyService
中注入 MyRepository
:
@AndroidEntryPoint
class MyService: Service() {
@Inject
lateinit var myRepository: MyRepository
...
}
@AndroidEntryPoint
class MyActivity: AppCompatActivity(R.layout.my_layout) {
@Inject
lateinit var myRepository: MyRepository
...
}
记住:
Fields injected by Hilt cannot be private
这是 Hilt 支持的 Android 类。
如果您想知道 Hilt 不支持 类(例如:ContentProvider
)怎么办?!我建议学习本教程 @EntryPoint annotation on codelab (also don't forget to check the documentation for how to Inject dependencies in classes not supported by Hilt).
此外,如果您在服务中重写 onCreate - 不要忘记添加 super.onCreate() 否则您将获得无法初始化 myRepository 值的运行时异常(我曾为这个错误苦苦挣扎了一段时间在重构我的服务期间,也许对某些人有帮助)
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
override fun onCreate() {
super.onCreate()
}
}
我有一个带有 Hilt 依赖项注入的 Android 项目。我定义了 MyApplication
和 MyModule
如下。
@HiltAndroidApp
class MyApplication : Application()
@Module
@InstallIn(ApplicationComponent::class)
abstract class MyModule {
@Binds
@Singleton
abstract fun bindMyRepository(
myRepositoryImpl: MyRepositoryImpl
): MyRepository
}
MyRepositoryImpl
实现了 MyRepository
接口:
interface MyRepository {
fun doSomething(): String
}
class MyRepositoryImpl
@Inject
constructor(
) : MyRepository {
override fun doSomething() = ""
}
我现在可以将 MyRepository
的这个实现注入到 ViewModel 中:
class MyActivityViewModel
@ViewModelInject
constructor(
private val myRepository: MyRepository,
) : ViewModel() { }
这按预期工作。但是,如果我尝试将存储库注入服务,则会收到错误 java.lang.Class<MyService> has no zero argument constructor
:
class MyService
@Inject
constructor(
private val myRepository: MyRepository,
): Service() { }
activity 也会出现同样的错误:
class MyActivity
@Inject
constructor(
private val myRepository: MyRepository,
) : AppCompatActivity(R.layout.my_layout) { }
我注射有什么问题?
您在 MyService
class 上使用 @Inject
就好像 MyService
是在其他位置注入的。
如果我没理解错的话,你想要更类似于:
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
}
从关于我们如何 Inject dependencies into Android classes 的文档中,我们可以了解到以下内容:
Hilt can provide dependencies to other Android classes that have the @AndroidEntryPoint annotation.
Hilt currently supports the following Android classes:
Application
(by using@HiltAndroidApp
)Activity
Fragment
View
Service
BroadcastReceiver
因此,当您对这些 Android 类 中的任何一个进行子类化时,您不会要求 Hilt 通过构造函数注入依赖项。相反,您使用 @AndroidEntryPoint
注释它,并要求 Hilt 通过使用 @Inject
:
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject
lateinit var mAdapter: SomeAdapter
...
}
因此,在您的情况下,您应该像这样在 MyActivity
和 MyService
中注入 MyRepository
:
@AndroidEntryPoint
class MyService: Service() {
@Inject
lateinit var myRepository: MyRepository
...
}
@AndroidEntryPoint
class MyActivity: AppCompatActivity(R.layout.my_layout) {
@Inject
lateinit var myRepository: MyRepository
...
}
记住:
Fields injected by Hilt cannot be private
这是 Hilt 支持的 Android 类。
如果您想知道 Hilt 不支持 类(例如:ContentProvider
)怎么办?!我建议学习本教程 @EntryPoint annotation on codelab (also don't forget to check the documentation for how to Inject dependencies in classes not supported by Hilt).
此外,如果您在服务中重写 onCreate - 不要忘记添加 super.onCreate() 否则您将获得无法初始化 myRepository 值的运行时异常(我曾为这个错误苦苦挣扎了一段时间在重构我的服务期间,也许对某些人有帮助)
@AndroidEntryPoint
class MyService : Service() {
@Inject
lateinit var myRepository: MyRepository
override fun onCreate() {
super.onCreate()
}
}