简体   繁体   English

使用 Hilt 将存储库注入 Android 中的服务

[英]Injecting a repository into a Service in Android using Hilt

I have an Android project with Hilt dependency injection.我有一个带有 Hilt 依赖注入的 Android 项目。 I have defined MyApplication and MyModule as follows.我已经定义了MyApplicationMyModule如下。

@HiltAndroidApp
class MyApplication : Application()

@Module
@InstallIn(ApplicationComponent::class)
abstract class MyModule {
    @Binds
    @Singleton
    abstract fun bindMyRepository(
        myRepositoryImpl: MyRepositoryImpl
    ): MyRepository
}

MyRepositoryImpl implements the MyRepository interface: MyRepositoryImpl实现了MyRepository接口:

interface MyRepository {
    fun doSomething(): String
}

class MyRepositoryImpl
@Inject
constructor(

) : MyRepository {
    override fun doSomething() = ""
}

I can now inject this implementation of MyRepository into a ViewModel:我现在可以将MyRepository的这个实现注入到 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 :但是,如果我尝试将存储库注入服务,则会收到错误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?我在注射时做错了什么?

From the documentation on how we Inject dependencies into Android classes , we can learn the following:从我们如何将依赖项注入 Android 类的文档中,我们可以了解到以下内容:

Hilt can provide dependencies to other Android classes that have the @AndroidEntryPoint annotation. Hilt 可以为其他具有 @AndroidEntryPoint 注解的 Android 类提供依赖项。

Hilt currently supports the following Android classes: Hilt 目前支持以下 Android 类:

  • Application (by using @HiltAndroidApp ) Application (通过使用@HiltAndroidApp
  • ViewModel (by using @HiltViewModel ) ViewModel (通过使用@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.因此,当您对这些 Android 类中的任何一个进行子类化时,您不会要求 Hilt 通过构造函数注入依赖项。 Instead, you annotate it with @AndroidEntryPoint , and ask Hilt to inject its dependencies by annotating the property with @Inject :相反,您使用@AndroidEntryPoint注释它,并要求 Hilt 通过使用@Inject注释属性来注入其依赖项:

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { 

    @Inject
    lateinit var mAdapter: SomeAdapter 

    ...

}

So, in your case you should inject MyRepository in MyActivity and MyService like this:因此,在您的情况下,您应该像这样在MyActivityMyService中注入MyRepository

@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 Hilt 注入的字段不能私有

That's it for Android classes that is supported by Hilt.这就是 Hilt 支持的 Android 类。

If you wonder what about classes not supported by Hilt (ex: ContentProvider )?!如果您想知道 Hilt 不支持的类(例如: 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 ).我建议从本教程中学习如何使用codelab 上的 @EntryPoint 注释(也不要忘记查看文档以了解如何在 Hilt 不支持的类中注入依赖项)。

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)此外,如果您在服务中覆盖 onCreate - 不要忘记添加 super.onCreate() 否则您将获得无法初始化 myRepository 值的运行时异常(我在重构我的服务期间一直在努力解决此错误,所以也许它会对某人有所帮助)

@AndroidEntryPoint
class MyService : Service() {
    @Inject
    lateinit var myRepository: MyRepository

    override fun onCreate() {
        super.onCreate()

    }
}

Your use of @Inject on the MyService class is as if MyService is to be injected at some other location.您在MyService类上使用@Inject就好像要在其他位置注入MyService

If I understand correctly, you want something more akin to:如果我理解正确,您想要更类似于:

@AndroidEntryPoint
class MyService : Service() {

    @Inject
    lateinit var myRepository: MyRepository

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM