如何在带有刀柄的 CoroutineWorker 中使用依赖注入?

How can I use dependency injection in CoroutineWorker with hilt?

我正在学习依赖注入,以下代码A和代码B来自项目https://github.com/android/sunflower

作者在代码A中定义了一个依赖注入PlantDao,但是在代码B中用代码database.plantDao()手动创建了一个PlantDao对象

为什么作者不对代码 B 中的对象 PlantDao 使用依赖注入?如何在代码 B 中对对象 PlantDao 使用依赖注入?

代码A

@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {

    @Singleton
    @Provides
    fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
        return AppDatabase.getInstance(context)
    }

    @Provides
    fun providePlantDao(appDatabase: AppDatabase): PlantDao {
        return appDatabase.plantDao()
    }

   ...
}

代码B

class SeedDatabaseWorker(
        context: Context,
        workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        try {
            val filename = inputData.getString(KEY_FILENAME)
            if (filename != null) {
                applicationContext.assets.open(filename).use { inputStream ->
                    JsonReader(inputStream.reader()).use { jsonReader ->
                        ...
                        val database = AppDatabase.getInstance(applicationContext)
                        database.plantDao().insertAll(plantList)

                        ...
            } else {
               ...
            }
        } catch (ex: Exception) {
           ...
        }
    }

    ..
}

添加内容

致安德鲁:谢谢!

在这个中,你告诉我@InstallIn(SingletonComponent::class)将对整个应用程序可用,你可以看图1。

作者在代码A中定义了一个PlantDao的依赖注入对象,安装为SingletonComponent::class.

所以我认为PlantDao的对象对整个应用程序都是可用的,为什么我不能直接在代码B中使用PlantDao的依赖注入对象呢?

图片 1

代码D

class SeedDatabaseWorker @Inject  constructor(
    database: AppDatabase,
    context: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        try {
            val filename = inputData.getString(KEY_FILENAME)
            if (filename != null) {
                applicationContext.assets.open(filename).use { inputStream ->
                    JsonReader(inputStream.reader()).use { jsonReader ->
                        ...                  
                        database.plantDao().insertAll(plantList)
                        ...
                    } else {   
                ..
        }

您必须使用 @HiltWorker 注释您的 worker,使用 @Assisted 注释您的上下文和参数,使用 @AssistedInject 注释您的构造函数,然后您可以构造函数注入您的 dao。

工人代码

@HiltWorker
class SeedDatabaseWorker @AssistedInject constructor(
        @Assisted context: Context,
        @Assisted workerParams: WorkerParameters,
        private val database: AppDatabase
) : CoroutineWorker(context, workerParams) {
    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        try {
            val filename = inputData.getString(KEY_FILENAME)
            if (filename != null) {
                applicationContext.assets.open(filename).use { inputStream ->
                    JsonReader(inputStream.reader()).use { jsonReader ->
                        ...
                        database.plantDao().insertAll(plantList)

                        ...
            } else {
               ...
            }
        } catch (ex: Exception) {
           ...
        }
    }

    ..
}

此外,您必须将默认的 WorkerFactory 更改为 hiltWorkerFactory 并删除默认的初始化程序:

AppCode

@HiltAndroidApp
class ExampleApplication : Application(), Configuration.Provider {

  @Inject lateinit var workerFactory: HiltWorkerFactory

  override fun getWorkManagerConfiguration() =
      Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
}

AndroidManifest.xml

<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />

需要依赖项

implementation 'androidx.hilt:hilt-work:1.0.0'
kapt 'androidx.hilt:hilt-compiler:1.0.0'
implementation 'androidx.work:work-runtime-ktx:2.5.0'

请注意,稍后将 androidx.work 更新到 2.6 时,某些流程会发生变化。你可以阅读更多here

编辑

你可以直接在代码b中使用你的依赖注入plantdao。这就是构造函数中 private val database: AppDatabase 的含义。在第一步中,您将 plantdao 提供给 hilt 并告诉它如何创建 plantdao 的实例。在下一步(代码 b)中,您通过构造函数注入它来保留 plantdao 的实例。您必须首先将它提供给 hilt(通过模块),然后您可以保留它(通过构造函数注入)。