androidkotlindagger-hiltandroid-workmanagercoroutineworker

Hilt + Worker NoSuchMethodException: <init> [class android.content.Context, class androidx.work.WorkerParameters]


I encountered an exception while trying to enqueue a work using Hilt and WorkManager:

Could not instantiate my.example.package.widget.ExampleWorker
                 java.lang.NoSuchMethodException: my.example.package.widget.ExampleWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
                    at java.lang.Class.getConstructor0(Class.java:3325)
                    at java.lang.Class.getDeclaredConstructor(Class.java:3063)
                    at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:95)
                    at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
                    at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:145)
                    at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
                    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
                    at java.lang.Thread.run(Thread.java:1012)
14:26:51.737  E  Could not create Worker my.example.package.widget.ExampleWorker

Here's my Worker class:

@HiltWorker
class ExampleWorker @AssistedInject constructor(
    @Assisted private val context: Context,
    @Assisted workerParameters: WorkerParameters,
    private val exampleUseCase: ExampleUseCase
) : CoroutineWorker(context, workerParameters) {

    companion object {

        private val uniqueWorkName = ExampleWorker::class.java.simpleName

        fun enqueue(context: Context) {
            val manager = WorkManager.getInstance(context)
            val requestBuilder = PeriodicWorkRequestBuilder<ExampleWorker>(
                Duration.ofMinutes(15)
            )

            manager.enqueueUniquePeriodicWork(
                uniqueWorkName,
                ExistingPeriodicWorkPolicy.UPDATE,
                requestBuilder.build()
            )
        }
    }

    override suspend fun doWork(): Result {
        exampleUseCase.invoke()
        return Result.success()
    }
}

My HiltApp:

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

    // https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
    @Inject
    lateinit var workerFactory: HiltWorkerFactory

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

In the AndroidManifest.xml file, I removed the default initializer as per the tutorial: https://developer.android.com/guide/background/persistent/configuration/custom-configuration#remove-default

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

The simplified class I'm injecting in my worker:

class ExampleUseCase @Inject constructor() {
    operator fun invoke() {}
}

Here are my dependencies:

implementation("com.google.dagger:hilt-android:2.48.1")
ksp("com.google.dagger:hilt-android-compiler:2.48.1")

implementation("androidx.hilt:hilt-work:1.0.0")
ksp("androidx.hilt:hilt-compiler:1.0.0")

implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("androidx.work:work-runtime:2.8.1")

Gradle plugin version: 8.1.1, Kotlin version: 1.9.10

I encountered this exception after updating several dependencies in my project, such as the Gradle Plugin from 7.4.1 to 8.1.1, Kotlin from 1.8.0 to 1.9.10, Hilt from 2.44.2 to 2.48.1, and the compile SDK from 33 to 34, among others.

I attempted to downgrade Hilt, however, in doing so, I encountered new exceptions, which I believe may be caused by version incompatibilities among all these upgraded libraries.

If I remove the exampleUseCase parameter from the worker constructor, the NoSuchMethodException is resolved. However, I require this field in the doWork() method. I attempted to inject it as lateinit var, but it isn't initialized by the time it is called.

I've checked a lot of documentation, but I'm still missing something. I would greatly appreciate any help!


Solution

  • I think that's a bug in KSP, see this