Ícaro
Ícaro

Reputation: 1610

Android Work Manager: "Could not instantiate Worker"

I've followed the Android Developer's tutorial on using the Worker Manager structure to run my code in background but anytime I try to enqueue my worker it doesn't run and I get the following error:

2018-10-04 22:25:47.004 28669-28885/app.package.com.debug E/DefaultWorkerFactory: Could not instantiate app.package.com.MyWorker
    java.lang.NoSuchMethodException: <init> []
        at java.lang.Class.getConstructor0(Class.java:2320)
        at java.lang.Class.getDeclaredConstructor(Class.java:2166)
        at androidx.work.DefaultWorkerFactory.createWorker(DefaultWorkerFactory.java:58)
        at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:180)
        at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:117)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
2018-10-04 22:25:47.005 28669-28885/app.package.com.debug E/WorkerWrapper: Could for create Worker app.package.com.MyWorker

I've seen that this problem could be related to the default constructor on the worker but I already use the correct one instead of the deprecated default function.

My worker is declared as:

public class MyWorker extends Worker {

    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        // Doesn't even get called
    }
}

And it gets queued like so:

WorkManager workManager = WorkManager.getInstance();
if (myWorkerRequest == null) {
    myWorkerRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
            .setConstraints(new Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .build())
            .build();
}
WorkStatus workStatus = workManager.getStatusById(myWorkerRequest.getId()).getValue();
if (workStatus == null || !workStatus.getState().isFinished()) {
    workManager.enqueue(myWorkerRequest);
}

I'm not seeing anything different from the examples so I'd like to understand what else could affect my code to cause this crash. Could it be something ProGuard related?

My version is 1.0.0-alpha09

Thanks!

Upvotes: 40

Views: 30157

Answers (15)

Ajinkya Kalaskar
Ajinkya Kalaskar

Reputation: 102

Add below dependency in build.gradle

    implementation("com.google.dagger:hilt-android:2.49")
    kapt("com.google.dagger:hilt-compiler:2.49")
    implementation("androidx.hilt:hilt-work:1.1.0")
    kapt("androidx.hilt:hilt-compiler:1.1.0")
    kapt("com.google.dagger:hilt-android-compiler:2.49")
    implementation("androidx.hilt:hilt-navigation-fragment:1.1.0")
    implementation ("androidx.work:work-runtime-ktx:$workManagerVersion")
    implementation ("androidx.work:work-runtime:$workManagerVersion")

Add below code in Manifest

<provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <meta-data
            android:name="androidx.work.WorkManagerInitializer"
            android:value="androidx.startup"
            tools:node="remove" />
    </provider>

Your Application class

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

    @Inject lateinit var workerFactory: HiltWorkerFactory
    override val workManagerConfiguration: Configuration
        get() = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
    
}

And Your Worker class

@HiltWorker
class ImageFormUpload @AssistedInject constructor(
    @Assisted appContext: Context, @Assisted params: WorkerParameters,
    private val notificationBuilder: NotificationCompat.Builder,
    private val notificationManager: NotificationManagerCompat
) : CoroutineWorker(appContext, params) {
    companion object {
        private const val TAG = "ImageFormUpload"
    }

    override suspend fun doWork(): Result {
       Log.d(TAG, "doWork: Worked thread")

        return Result.success()
    }
}

Upvotes: 1

ka3ak
ka3ak

Reputation: 3181

As I had to update

implementation 'androidx.work:work-runtime:2.5.0'

to

implementation 'androidx.work:work-runtime:2.7.1'

and WorkManagerInitializer wasn't available in the last version the following change in AndroidManifest.xml resolved the issue:

Before:

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

After:

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

The solution with "merge" suggested by others still caused the error.

Upvotes: 0

startoftext
startoftext

Reputation: 3916

Try downgrading from OneSignal 4.8.5+ to 4.8.4.

Just in case you tried all the above solutions and are still having problems with Hilt Workers. OneSignal 4.8.5 introduced a bug that initialized the WorkManager before hilt could do so. I noticed it because in my application class getWorkManagerConfiguration() was never called. Downgrading to OneSignal 4.8.4. It took me a couple days to figure this out.

There is a bug filed here: https://github.com/OneSignal/OneSignal-Android-SDK/issues/1748

Upvotes: 0

This issue came to me when i copy pasted Worker class to create new Worker class

Solution

Clean Project and Running app solved my issue

Upvotes: 0

Narek Hayrapetyan
Narek Hayrapetyan

Reputation: 1919

I've added this kapt "androidx.hilt:hilt-compiler:1.0.0" dependency in the app.gradle and error has gone.

Upvotes: 4

Udayaditya Barua
Udayaditya Barua

Reputation: 1162

I found another case where you might run into NoSuchMethodException

If you have these gradle properties enabled:

kapt.classloaders.cache.size=6

kapt.include.compile.classpath=false

this does aggressive caching of KAPT which results in WorkManager not initialized by hilt

I removed these properties and it worked.

Upvotes: 0

thegirlincode
thegirlincode

Reputation: 404

I faced the same issue and my solution is here

  1. I update work manager version "2.6.0-alpha02" previous version was "2.5.0"
  2. You need to add provider with meta-data into the manifest.

    <provider
      android:name="androidx.startup.InitializationProvider"
      android:authorities="${applicationId}.androidx-startup"
      android:exported="false"
      tools:node="merge">
      <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
    </provider>

  1. You need to inject HiltWorkerFactory to Application class and setWorkerFactory

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

@Inject
lateinit var workerFactory: HiltWorkerFactory

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

Upvotes: 8

Abhijith mogaveera
Abhijith mogaveera

Reputation: 1284

I got the same error then i realized to add app start up library which resolved my issue

manifest file

<provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <meta-data
            android:name="androidx.work.WorkManagerInitializer"
            android:value="androidx.startup"
            tools:node="remove" />
    </provider>

build.gradle.app

 def work_version = "2.6.0"
    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"
    implementation 'androidx.hilt:hilt-work:1.0.0'
    kapt "com.google.dagger:hilt-android-compiler:2.37"

    //app start up
    implementation("androidx.startup:startup-runtime:1.1.0")

i just added app startup library and set up in Android menifest

Upvotes: 2

gardenapple
gardenapple

Reputation: 195

In addition to Tony's answer:

Another thing to keep in mind if you're using Kotlin is that the Worker class can be nested, but it cannot be marked as inner.

I suspect that if you're using Java, you might also be able to use a nested class if you mark it as static. But I haven't tested this.

Upvotes: 6

Ace
Ace

Reputation: 2218

If you are using Worker with Hilt, then, in addition to all other requirements, make sure you are also adding HiltWorkerFactory to your Application class

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

    @Inject
    lateinit var workerFactory: HiltWorkerFactory

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

Upvotes: 5

Luja93
Luja93

Reputation: 483

If you are using on-demand initialization and Dagger to inject the whole configuration, make sure to remove WorkManager default initialization by adding the following provider in AndroidManifest, as suggested by the pull request. This was the only thing which helped me. For more details, check the blog.

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

Upvotes: 16

Brian
Brian

Reputation: 131

The problem for me was the constructor of my kotlin class:

WRONG

class MyWorker(val app: Application, workerParams: WorkerParameters): Worker(app, workerParams)

GOOD

class MyWorker(val context: Context, workerParams: WorkerParameters): Worker(context, workerParams)

Upvotes: 13

Tony
Tony

Reputation: 2451

I had the same issue. The cause of the issue for me was that my Worker class was a nested class. The moment I made it an independent class, it worked.

Upvotes: 38

Michalsx
Michalsx

Reputation: 3621

I had this problem in stable version 1.0.0 and I fixed it by making my worker class public.

class MyWorker extends Worker {...} > public class MyWorker extends Worker {...}

Upvotes: 9

ianhanniballake
ianhanniballake

Reputation: 199805

This is a known issue with WorkManager 1.0.0-alpha09 that is already marked as fixed for alpha10.

As a workaround, you can add the following lines to your proguard configuration:

-keepclassmembers class * extends androidx.work.Worker {
    public <init>(android.content.Context,androidx.work.WorkerParameters);
}

Upvotes: 19

Related Questions