Начиная с версии 1.0.0-beta01 , здесь приведена реализация инъекции Кинжала с WorkerFactory.
Концепция взята из этой статьи : https://medium.com/@nlg.tuan.kiet/bb9f474bde37 и я просто публикую свою собственную реализацию этого шага ( в Kotlin ).
==========
Чтоэта реализация пытается достичь:
Каждый раз, когда вы хотите добавить зависимость к работнику, вы помещаете эту зависимость в связанный класс работника
===========
1. Добавить интерфейс для всех рабочих завода
IWorkerFactory.kt
interface IWorkerFactory<T : ListenableWorker> {
fun create(params: WorkerParameters): T
}
2. Добавить простой рабочий класс с фабрикой , который реализует IWorkerFactory , а также с зависимостью для этого работника
HelloWorker.kt
class HelloWorker(
context: Context,
params: WorkerParameters,
private val apiService: ApiService // our dependency
): Worker(context, params) {
override fun doWork(): Result {
Log.d("HelloWorker", "doWork - fetchSomething")
return apiService.fetchSomething() // using Retrofit + RxJava
.map { Result.success() }
.onErrorReturnItem(Result.failure())
.blockingGet()
}
class Factory @Inject constructor(
private val context: Provider<Context>, // provide from AppModule
private val apiService: Provider<ApiService> // provide from NetworkModule
) : IWorkerFactory<HelloWorker> {
override fun create(params: WorkerParameters): HelloWorker {
return HelloWorker(context.get(), params, apiService.get())
}
}
}
3. Добавление WorkerKey для Dagger's multi-binding
WorkerKey.kt
@MapKey
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class WorkerKey(val value: KClass<out ListenableWorker>)
4. Add модуль Dagger для мультисвязывающего работника (на самом деле мультисвязывает с завода)
WorkerModule.kt
@Module
interface WorkerModule {
@Binds
@IntoMap
@WorkerKey(HelloWorker::class)
fun bindHelloWorker(factory: HelloWorker.Factory): IWorkerFactory<out ListenableWorker>
// every time you add a worker, add a binding here
}
5. Поместите WorkerModule в AppComponent .Здесь я использую dagger-android для создания класса компонента
AppComponent.kt
@Singleton
@Component(modules = [
AndroidSupportInjectionModule::class,
NetworkModule::class, // provides ApiService
AppModule::class, // provides context of application
WorkerModule::class // <- add WorkerModule here
])
interface AppComponent: AndroidInjector<App> {
@Component.Builder
abstract class Builder: AndroidInjector.Builder<App>()
}
6. Добавление пользовательского WorkerFactory в использовать возможность создания работника с момента выпуска версии 1.0.0-alpha09
DaggerAwareWorkerFactory.kt
class DaggerAwareWorkerFactory @Inject constructor(
private val workerFactoryMap: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<IWorkerFactory<out ListenableWorker>>>
) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
val entry = workerFactoryMap.entries.find { Class.forName(workerClassName).isAssignableFrom(it.key) }
val factory = entry?.value
?: throw IllegalArgumentException("could not find worker: $workerClassName")
return factory.get().create(workerParameters)
}
}
7. В классе приложений замените WorkerFactory на свой собственный:
App.kt
class App: DaggerApplication() {
override fun onCreate() {
super.onCreate()
configureWorkManager()
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this)
}
@Inject lateinit var daggerAwareWorkerFactory: DaggerAwareWorkerFactory
private fun configureWorkManager() {
val config = Configuration.Builder()
.setWorkerFactory(daggerAwareWorkerFactory)
.build()
WorkManager.initialize(this, config)
}
}
8. Не забудьте отключить инициализацию менеджера работы по умолчанию
AndroidManifest.xml
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:enabled="false"
android:exported="false"
tools:replace="android:authorities" />
Вот и все.
Каждый раз, когда вы хотите добавитьзависимость от работника, вы помещаете зависимость в связанный рабочий класс (например, HelloWorker здесь).
Каждый раз, когда вы хотите добавить работника, реализуйте фабрику в рабочем классе и добавьте фабрику работника в WorkerModuleдля мульти-связывания.
Для получения более подробной информации, например, с помощью AssistedInject для сокращения стандартных кодов,пожалуйста, обратитесь к статье, которую я упомянул в начале.