首页 > 解决方案 > WorkManager 不使用自定义配置

问题描述

我正在尝试使用 运行同步作业,WorkManager但是似乎传递的配置被部分忽略了。

下面是我的实现:

应用程序:

class App : Application(), HasAndroidInjector, Configuration.Provider {
@Inject
    lateinit var workerConfiguration: Configuration
override fun getWorkManagerConfiguration(): Configuration {
        Timber.tag(javaClass.name).d("RRR config ${workerConfiguration.executor.run { Thread.currentThread().name }}")
        return workerConfiguration
    }
}

模块注入:如您所见,我设置了 1 个 SingleThreaded Executor 与一些特定ThreadFactory和自定义WorkerFactory

@Singleton
@Provides
    fun provideWorkManagerConfiguration(
        globalWorkerFactory: GlobalWorkerFactory
    ): Configuration {
        val threadFactory = ThreadFactoryBuilder().setNameFormat("sync-worker-thread-%d").build()
        val executor = Executors.newSingleThreadExecutor(threadFactory)
        executor.submit { Log.d(javaClass.name,"RRR executor thread = ${Thread.currentThread().name}") }
        return Configuration.Builder()
            .setWorkerFactory(globalWorkerFactory)
            .setExecutor(executor)
            .build()
    }

GlobalWorkingFactory:用于向workers注入一些参数

@Singleton
class GlobalWorkerFactory @Inject constructor(
    api: API
) : DelegatingWorkerFactory() {
    init {
        Log.d(javaClass.name, "RRR adding factory ${Thread.currentThread().name}")
        addFactory(WorkerFactory(api))
    }
}

工人工厂:

CustomWorkerFactory(
    private val api: API,
) : WorkerFactory() {

    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): CoroutineWorker? {
        return when (workerClassName) {
            SyncWorker::class.java.name -> {
                Log.d(javaClass.name, "RRR gettting sync worker on ${Thread.currentThread().name}")
                SyncWorker(appContext, workerParameters, api)
            }
            else ->
                null
        }
    }
}

Sync Worker 执行一些长时间运行的调用:


class SyncWorker constructor(
    appContext: Context,
    workerParams: WorkerParameters,
    private val api: API):
    CoroutineWorker(appContext, workerParams) {

override suspend fun doWork(): Result {

Timber.d("RRR START sync file ${uploadingFile.file.name} on thread ${Thread.currentThread().name}")

syncfile()

Timber.d("RRR returning result for ${uploadingFile.file.name}")

}

最后是我排队工作的方式:


fun addFileToWorker(context: Context, uploadingFile: UploadingFile) {
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .build()

            val syncWorkerRequest = OneTimeWorkRequestBuilder<SyncWorker>()
                .setInputData(
                    workDataOf(
                        "uploadingFile" to uploadingFileAdapter.toJson(
                            uploadingFile
                        )
                    )
                )
                .addTag(SYNC_WORK_TAG)
                .setConstraints(constraints)
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)
                .build()

            val operation = WorkManager.getInstance(context)
                .enqueueUniqueWork(
                    Sunique_ID_for_each_job
                    ExistingWorkPolicy.KEEP,
                    syncWorkerRequest)
                .result
            operation.addListener({ Timber.d("RRR added file ${uploadingFile.file.name} ${Thread.currentThread().name}")}, { it.run() })
        }

下面是我如何获取它们的日志,它表明文件正在与分配的线程不同的线程上处理:


core.worker.GlobalWorkerFactory: RRR adding factory main
di.module.ApplicationModule: RRR executor thread = sync-worker-thread-0
Activity: RRR calling process sessions
App: RRR config main
Utils$Companion: RRR added file 0.aes pool-14-thread-2
Utils$Companion: RRR added file 1635858822 pool-14-thread-3
CustomWorkerFactory: RRR gettting sync worker on pool-14-thread-1
CustomWorkerFactory: RRR gettting sync worker on pool-14-thread-2
SyncWorker: RRR START sync file 0.aes on thread DefaultDispatcher-worker-1
SyncWorker: RRR START sync file 1635858822 on thread DefaultDispatcher-worker-4
SyncWorker: RRR START sync file 0.aes on thread DefaultDispatcher-worker-3

由于我已经明确定义了 1 个线程并且我成功地将我的线程的配置传递给 GlobalWorkerFactory,所以它不应该尊重第一个日志中看到的线程吗?即:sync-worker-thread-0

我看到其他帖子建议只APPEND向一名工人工作,但我认为这不是它的用途。即便如此,我指定的线程也不是用于有或没有 APPEND 的工作。

标签: androidmultithreadingandroid-workmanager

解决方案


来自有关工人的 Android 文档:Doc

注意 CoroutineWorker.doWork() 是一个挂起函数。与 Worker 不同,此代码不会在您的配置中指定的 Executor 上运行。相反,它默认为 Dispatchers.Default。您可以通过提供自己的 CoroutineContext 来自定义它。在上面的示例中,您可能希望在 Dispatchers.IO 上执行此工作,如下所示:

class CoroutineDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        withContext(Dispatchers.IO) {
            val data = downloadSynchronously("https://www.google.com")
            saveData(data)
            return Result.success()
        }
    }
}

就我而言,我创建了一个newSingleThreadContext并将其传递给我的工人。


推荐阅读