Android Work Manager:"无法实例化工作者"

39

我按照Android开发者的教程使用Worker Manager结构来在后台运行我的代码,但每当我尝试将worker加入队列时,它不会运行并且出现以下错误:

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

我看到这个问题可能与工作者的默认构造函数有关,但我已经使用了正确的构造函数而不是废弃的默认函数。
我的工作者声明为:
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
    }
}

然后它就像这样排队:

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);
}

我没有看到与示例不同的任何内容,所以我想了解还有什么可能影响我的代码导致崩溃。这可能与ProGuard有关吗?

我的版本是1.0.0-alpha09

谢谢!

14个回答

37

我也遇到了相同的问题。对我来说,问题的原因是我的Worker类是一个嵌套类。当我将其变为独立的类时,问题得到了解决。


2
这也解决了我的问题。添加proguard排除并没有用。 - Christian.D
4
谢谢,你救了我的一天!只有独立班级!但是有什么区别? - thecr0w

19

这是一个与WorkManager 1.0.0-alpha09相关的已知问题,已经在alpha10中标记为已修复。

作为解决方法,您可以将以下行添加到您的proguard配置中:

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

2
@ianhanniballake 所以... 即使你不使用它,你仍然需要添加 proguard 限制吗? - Damiii
6
我一直面临着与1.0.0-beta01相同的问题,似乎我的自定义Worker的构造函数是package-private。为了让WorkManager正常工作,它需要是public的。我将构造函数改为public后,它运行得很好。 - Rickyy
1
在我的情况下,我将类设置为默认修饰符,然后将其设置为public,这样就可以正常工作了。 - anshul
在 android.arch.work:work-runtime:1.0.1 (Android 模拟器 9.0) 上仍然存在此异常。您是否已升级到1.0.1?@ianhanniballake - thecr0w
2
在2.2.0版本中出现了相同的异常。 - thecr0w
对我没用(使用Hilt和RxWorker):我不得不从2.6.0-alpha02降级到2.5.0。 - Pat Lee

15

如果您正在使用按需初始化和Dagger来注入整个配置,请确保通过在AndroidManifest中添加以下提供者来删除WorkManager的默认初始化,正如拉取请求所建议的。这是唯一帮助我的事情。有关更多详细信息,请查看博客

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

3
非常有帮助。更多说明可以在官方文档中找到:https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration - Mitch
1
我升级到了2.6版本,它的默认初始化方式已经改变,这就是导致我的问题的原因。 - Hussien Fahmy

10
对我来说问题出在我的 Kotlin 类的构造函数上:

错误示例

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

好的

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

1
这是最正确的答案。在WorkManager代码的深处,有一个WorkerFactory接口的实现,它根据上下文和workerParams创建一个Worker。 - nbtk

9

我在稳定版本1.0.0中遇到了这个问题,通过将我的worker类设置为public,我解决了这个问题。

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

7

我遇到了同样的问题,我的解决方案在这里

  1. 我更新了工作管理器版本,"2.5.0" 升级至 "2.6.0-alpha02"
  2. 您需要将提供程序与元数据添加到清单中。

    <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. 你需要将HiltWorkerFactory注入到Application类,并设置WorkerFactory

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

@Inject
lateinit var workerFactory: HiltWorkerFactory

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


6

除了Tony的答案外:

如果使用Kotlin,另一件需要记住的事情是Worker类可以是嵌套的,但不能标记为inner

我猜如果你在使用Java,你也可以使用嵌套类,如果你将它标记为static。但我没有测试过。


1
在Java中,对我来说解决方案是添加“static”。我只需要在“Worker”构造函数中存储“context”,以便在“doWork()”中重用它。 - Salvador
是的,这个答案适用于嵌套的工作类。谢谢。我最终也像Salvador一样做了,它完美地运行了。 - Max

4
如果您正在使用WorkerHilt,那么除了满足所有其他要求高级自定义配置之外,还需确保在您的Application类中添加HiltWorkerFactory
@HiltAndroidApp
class App: Application(), Configuration.Provider {

    @Inject
    lateinit var workerFactory: HiltWorkerFactory

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

2

我遇到了相同的错误,后来意识到需要添加应用程序启动库才能解决我的问题。

清单文件

<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")

我刚刚添加了应用启动库,并在Android清单文件中设置。


1

我在 app.gradle 文件中添加了 kapt "androidx.hilt:hilt-compiler:1.0.0" 依赖项,错误已经解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接