Внедрение кинжала в Workamanager AssistedInject_AppAssistedInjectModule - PullRequest
0 голосов
/ 10 февраля 2020

Я хочу добавить репозитории и другие в рабочий менеджер. Так как workmanager и Android Component, я не могу просто вводить вещи в construcotr, но мне нужно создать класс Factory. Итак, я нашел пример на Medium и последовал ему. У меня есть зависимости

// Dagger 2
    def dagger_version = '2.24'
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android-support:$dagger_version"
    annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"

    // Assisted Injection
    def dagger_assist_version = '0.3.3'
    implementation "com.squareup.inject:assisted-inject-annotations-dagger2:$dagger_assist_version"
    kapt "com.squareup.inject:assisted-inject-processor-dagger2:$dagger_assist_version"

Затем у меня есть модуль WorkManager, где я связываю свою фабрику WorkerClass

@Module
interface WorkManagerModule {

    @Binds
    @IntoMap
    @WorkManagerKey(FileSplitter::class)
    fun bindImageSplitterWorker(factory: FileSplitter.Factory): ChildWorkerFactory

}

WorkManagerComponent


@Component(modules = [AppAssistedInjectModule::class, WorkManagerModule::class])
interface WorkManagerComponent {
    fun factory(): AppWorkerFactory
}

И фабрики

class AppWorkerFactory @Inject constructor(
    private val workerFactories: Map<Class<out CoroutineWorker>,
            @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): CoroutineWorker? {
        val foundEntry =
            workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
        val factoryProvider = foundEntry?.value
            ?: throw IllegalArgumentException("unknown worker class name: $workerClassName")
        return factoryProvider.get().create(appContext, workerParameters)
    }
}


interface ChildWorkerFactory {
    fun create(appContext: Context, params: WorkerParameters): CoroutineWorker
}

И класс Application, в котором я хочу построить DaggerComponent

        val factory: AppWorkerFactory = DaggerWorkManagerComponent.create().factory()
        WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(factory).build())

Так что мой класс WorkManager похож на

class FileSplitter @AssistedInject constructor(
    @Assisted private val appContext: Context,
    @Assisted private val params: WorkerParameters,
    @Assisted private val messagesRepository: MessagesRepository
) : CoroutineWorker(appContext, params) {

    override val coroutineContext = Dispatchers.IO

    override suspend fun doWork(): Result = coroutineScope {
        ... CODE...
        Result.success()
    }

    @AssistedInject.Factory
    interface Factory : ChildWorkerFactory
    companion object {
        private const val TAG = "ImageSplitterWorker"
    }
}

При сборке Project я получаю несколько ошибок. Но первые две ошибки кажутся настоящей проблемой. Я не могу понять, в чем дело. Вот они.

...di/modules/AppAssistedInjectModule.java:7: error: cannot find symbol
@dagger.Module(includes = {AssistedInject_AppAssistedInjectModule.class})
                           ^
  symbol: class AssistedInject_AppAssistedInjectModule

..di//modules/AppAssistedInjectModule.java:8: error: [ComponentProcessor:MiscError] dagger.internal.codegen.ComponentProcessor was unable to process this class because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.
public abstract class AppAssistedInjectModule {

Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

Решением является приведенный ниже код (каждая часть представляет собой отдельный файл для моего проекта)

Импорт Gradle

// Dagger 2
    def dagger_version = '2.27'
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android:$dagger_version"
    implementation "com.google.dagger:dagger-android-support:$dagger_version"
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"

    // Assisted Injection
    def dagger_assist_version = '0.5.2'
    compileOnly "com.squareup.inject:assisted-inject-annotations-dagger2:$dagger_assist_version"
    kapt "com.squareup.inject:assisted-inject-processor-dagger2:$dagger_assist_version"

Класс Worker


class FileSplitterWorker @AssistedInject constructor(
    @Assisted private val appContext: Context,
    @Assisted private val params: WorkerParameters,
    private val messagesRepository: MessagesRepository
) : CoroutineWorker(appContext, params) {

    override suspend fun doWork(): Result {

        // Do Work with messageRepository

        return Result.success()
    }

    @AssistedInject.Factory
    interface Factory : ChildWorkerFactory
}

Создайте этот интерфейс

interface ChildWorkerFactory {
    fun create(appContext: Context, params: WorkerParameters): CoroutineWorker
}

И фабричный класс для рабочих

class AppWorkerFactory @Inject constructor(
    private val workerFactories: Map<Class<out CoroutineWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): CoroutineWorker? {
        val foundEntry =
            workerFactories.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
        val factoryProvider = foundEntry?.value
            ?: throw IllegalArgumentException("unknown worker class name: $workerClassName")
        return factoryProvider.get().create(appContext, workerParameters)
    }
}

Компонент App для Dagger должен быть похож на

@Singleton
@Component(
    modules = [
AndroidInjectionModule::class,
        AndroidSupportInjectionModule::class,
        AppAssistedInjectModule::class,
        WorkManagerModule::class,
        etc etc...
    ]
)
interface AppComponent {
    fun inject(application: MyApplication)

    fun workerFactory(): AppWorkerFactory

    @Component.Factory
    interface Factory {
        fun withContext(@BindsInstance application: MyApplication): AppComponent
    }
}


@Module(includes = [AssistedInject_AppAssistedInjectModule::class])
@AssistedModule
interface AppAssistedInjectModule

Модуль WorkerModule должен быть и Интерфейс


@Module(includes = [RepositoryModule::class, etc etc])
interface WorkManagerModule {

    @Binds
    @IntoMap
    @WorkManagerKey(FileSplitterWorker::class)
    fun bindFileSplitterWorker(factory: FileSplitterWorker.Factory): ChildWorkerFactory

}

И класс приложения

override fun onCreate() {
        super.onCreate()
        instance = this


        val daggerAppComponent = DaggerAppComponent.factory().withContext(this)
        daggerAppComponent.inject(this)
        val factory: AppWorkerFactory = daggerAppComponent.workerFactory()
        WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(factory).build())

}

companion object {
        private lateinit var instance: MyApplication

    }

И в конце вы должны объявить workmanager манифестом в теге приложения

<provider
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:authorities="${applicationId}.workmanager-init"
            android:exported="false"
            tools:node="remove" />
0 голосов
/ 11 февраля 2020

Ну .... похоже на Dagger2 Впрыск в рабочий менеджер еще не может быть сделан. Для этого в Github есть открытый вопрос. Любой, кто знает, пожалуйста, сообщите !!

...