【问题标题】:Implement an AndroidX Worker with custom parameters使用自定义参数实现 AndroidX Worker
【发布时间】:2019-05-09 07:44:37
【问题描述】:

我在我的项目中从Android Priority JobQueue library 迁移到AndroidX WorkManager,但它的构建方式是Worker 应该是这样的:

TaskSchedulerWorker.kt

class TaskSchedulerWorker(
    private val workManager: WorkManager = WorkManager.getInstance()
) : TaskScheduler {

    override fun execute(useCaseWrapper: UseCaseWrapper) {
        workManager.beginUniqueWork(
            useCaseWrapper.useCaseName,
            ExistingWorkPolicy.APPEND,
            OneTimeWorkRequest.from(UseCaseWrapperWorker::class.java)
        ).enqueue()
    }

    override fun onCancel(useCaseWrapper: UseCaseWrapper) {
        workManager.cancelUniqueWork(useCaseWrapper.useCaseName)
    }
}

UseCaseWrapperWorker.kt

class UseCaseWrapperWorker(
    context: Context, 
    params: WorkerParams,
    private val useCaseWrapper: UseCaseWrapper
) : Worker(context, params) {

    override fun doWork(): Result {
        return try {
            useCaseWrapper.execute()
            Result.success()
        } catch (ex: Exception) {
            ex.printStackTrace()
            Result.failure()
        }
    }
}

关键是,如果我尝试使用这些类运行我的应用程序,我会收到下一个错误:

2019-05-09 09:34:45.784 27260-27443/com.mobileapp.debug E/WM-WorkerFactory: Could not instantiate com.mobileapp.domain.jobqueue.UseCaseWrapperWorker
    java.lang.NoSuchMethodException: com.mobileapp.domain.jobqueue.UseCaseWrapperWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
        at java.lang.Class.getConstructor0(Class.java:2328)
        at java.lang.Class.getDeclaredConstructor(Class.java:2167)
        at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:92)
        at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:234)
        at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:128)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
2019-05-09 09:34:45.784 27260-27443/com.mobileapp.debug E/WM-WorkerWrapper: Could not create Worker com.mobileapp.domain.jobqueue.UseCaseWrapperWorker

因为Worker 构造函数不能有超过两个默认参数(ContextWorkerParameters)。

我无法弄清楚如何使用接收ContextWorkerParametersUseCaseWrapper 的构造函数来实现UseCaseWrapperWorker 类,并使用@987654336 从TaskSchedulerWorker 调用它@指令。


已编辑:

我尝试实现CustomWorkerFactoryCustomWorker 以将UseCaseWrapper 传递给它们。问题是我必须在Application#onCreate 方法(Android Developer Documentation)中初始化WorkManager,而此时我无法访问所需的UseCaseWrapper

TaskSchedulerWorker.kt

WorkManager init 应该在 Application#onCreate

class TaskSchedulerWorker(private val appContext: Context) : TaskScheduler {

    override fun execute(useCaseWrapper: UseCaseWrapper) {
        val workerFactory = CustomWorkerFactory(useCaseWrapper)
        val configuration = Configuration.Builder()
            .setWorkerFactory(workerFactory)
            .build()
        WorkManager.initialize(context, configuration)

        WorkManager.getInstance().beginWork(
            "uniqueWorkName",
            ExistingWorkPolicy.APPEND,
            OneTimeWorkRequest.from(CustomWorker::class.java)
        )
    }
}

CustomWorkerFactory.kt

class CustomWorkerFactory(private val useCaseWrapper: UseCaseWrapper) : WorkerFactory() {

    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? {
        return CustomWorker(appContext, workerParameters, useCaseWrapper)
    }
}

CustomWorker.kt

class CustomWorker(
    context: Context, 
    params: WorkerParameters
) : Worker(context, params) {

    private var useCaseWrapper: UseCaseWrapper? = null

    constructor(
        context: Context,
        params: WorkerParameters,
        useCaseWrapper: UseCaseWrapper
    ) : this(context, params) {
        this.useCaseWrapper = useCaseWrapper
    }

    override fun doWork(): Result {
        return useCaseWrapper?.let { useCaseWrapper ->
            try {
                useCaseWrapper.execute()
                Result.success()
            } catch (ex: Exception) {
                Result.failure()
            }
        } ?: Result.failure()
    }
}

RuntimeException 抛出的是:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mobileapp.debug/com.mobileapp.home.view.activity.HomeActivity}: java.lang.IllegalStateException: WorkManager is already initialized.  
Did you try to initialize it manually without disabling WorkManagerInitializer? See WorkManager#initialize(Context, Configuration) or the class levelJavadoc for more information.
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3086)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3229)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:6981)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
Caused by: java.lang.IllegalStateException: WorkManager is already initialized.  Did you try to initialize it manually without disabling WorkManagerInitializer? 
See WorkManager#initialize(Context, Configuration) or the class levelJavadoc for more information.
    at androidx.work.impl.WorkManagerImpl.initialize(WorkManagerImpl.java:137)
    at androidx.work.WorkManager.initialize(WorkManager.java:169)
    at com.mobileapp.domain.worker.TaskSchedulerWorker.execute(TaskSchedulerWorker.kt:20)
    at com.mobileapp.domain.usecase.UseCaseHandler.execute(UseCaseHandler.kt:41)
    at com.mobileapp.domain.usecase.UseCaseCall.execute(UseCaseCall.kt:50)
    at com.mobileapp.home.view.presenter.HomePresenter.getConfigurationJSON(HomePresenter.kt:107)
    at com.mobileapp.home.view.activity.HomeActivity.initComponents(HomeActivity.kt:107)
    at com.mobileapp.home.view.activity.HomeActivity.onCreate(HomeActivity.kt:67)
    at android.app.Activity.performCreate(Activity.java:7326)
    at android.app.Activity.performCreate(Activity.java:7317)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3066)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3229) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1926) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:6981) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445) 

有什么建议吗?

【问题讨论】:

  • 对于工人实施中的客户参数,我面临同样的问题java.lang.NoSuchMethodException:。你能解决这个问题吗?
  • 我试图解决同样的问题,并以您的代码为例。仅从清单文件中禁用了默认初始化程序,并且它定期运行。

标签: android kotlin androidx android-workmanager


【解决方案1】:

您应该使用自定义的 WorkerFactory 来初始化您的 Worker。见https://developer.android.com/reference/androidx/work/WorkerFactory

【讨论】:

  • 好的,解决了一半的问题。 WorkManager 必须在 Application.onCreate() 方法中初始化,此时我无法访问我的 UseCaseWrapper
【解决方案2】:

您需要禁用默认初始化程序

如果你想控制初始化过程,你必须禁用 默认初始化器,然后定义您自己的自定义配置。

禁用默认初始化程序

要提供您自己的配置, 您必须首先删除默认初始化程序。 为此,请使用合并规则更新 AndroidManifest.xml 工具:节点=“删除”:

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

https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration

【讨论】:

    猜你喜欢
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 2021-04-29
    • 2019-01-03
    • 1970-01-01
    相关资源
    最近更新 更多