Reputation: 1792
Please find, What is going wrong with below setup for dagger 2 and android workmanager.
WorkerKey.kt
import androidx.work.ListenableWorker
import dagger.MapKey
import kotlin.reflect.KClass
@MapKey
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class WorkerKey(val value: KClass<out ListenableWorker>)
DaggerWorkerFactory.kt
class DaggerWorkerFactory @Inject constructor(
private val workerFactories: Map<Class<out ListenableWorker>, @JvmSuppressWildcards Provider<ChildWorkerFactory>>
) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
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)
}
}
ChildWorkerFactory.kt
import android.content.Context
import androidx.work.ListenableWorker
import androidx.work.WorkerParameters
interface ChildWorkerFactory {
fun create(appContext: Context, params: WorkerParameters): ListenableWorker
}
WorkerModule.kt
import com.hardik.core.di.ChildWorkerFactory
import com.hardik.core.di.WorkerKey
import com.hardik.spendy.PrepopulateCategoryWorker
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
@Module
interface WorkerModule {
@Binds
@IntoMap
@WorkerKey(PrepopulateCategoryWorker::class)
fun bindPrepopulateCategoryWork(factory: PrepopulateCategoryWorker.Factory): ChildWorkerFactory
}
AppComponent.kt
@Singleton
@Component(
modules = [
AndroidInjectionModule::class,
AppModule::class,
DatabaseModule::class,
UseCaseModule::class,
ViewModelModule::class,
WorkerModule::class,
ActivityModule::class
]
)
interface AppComponent : AndroidInjector<SpendyApplication> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: SpendyApplication): Builder
fun build(): AppComponent
}
override fun inject(app: SpendyApplication)
}
PrepopulateCategoryWorker.kt
import android.content.Context
import android.util.Log
import androidx.work.ListenableWorker
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.hardik.core.di.ChildWorkerFactory
import com.hardik.repository.Repository
import javax.inject.Inject
import javax.inject.Provider
class PrepopulateCategoryWorker(
private val appContext: Context,
private val workerParams: WorkerParameters,
private val repository: Repository
) : Worker(appContext, workerParams) {
override fun doWork(): Result {
Log.i("Hardik", "Repository injected : $repository")
return Result.success()
}
class Factory @Inject constructor(
private val repository: Provider<Repository>
) : ChildWorkerFactory {
override fun create(appContext: Context, params: WorkerParameters): ListenableWorker {
return PrepopulateCategoryWorker(
appContext,
params,
repository.get()
)
}
}
}
MainActivity.kt
class MainActivity : DaggerAppCompatActivity() {
@Inject
lateinit var workerFactory: WorkerFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
}
}
HomeFragment.kt
private fun startPrepopulate() {
val request = OneTimeWorkRequestBuilder<PrepopulateCategoryWorker>().build()
val workManager = WorkManager.getInstance(requireContext())
workManager.enqueue(request)
}
Error Logs
e: C:\git\Spendy\app\build\tmp\kapt3\stubs\debug\com\hardik\spendy\di\AppComponent.java:8: error: [Dagger/MissingBinding] androidx.work.WorkerFactory cannot be provided without an @Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.hardik.spendy.SpendyApplication> {
^
androidx.work.WorkerFactory is injected at
com.hardik.spendy.ui.activity.MainActivity.workerFactory
com.hardik.spendy.ui.activity.MainActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.hardik.spendy.di.AppComponent ? com.hardik.spendy.di.ActivityModule_ContributeMainActivity.MainActivitySubcomponent]
Upvotes: 4
Views: 2369
Reputation: 157437
you have to tell Dagger how to inject the worker factory as well. Add
@Binds
fun bindWorkManagerFactory(factory: DaggerWorkerFactory): WorkerFactory
to your WorkerModule
Upvotes: 4