WorkManager 不使用自定义配置
WorkManager not working with Custom Configuration
我正在尝试使用 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 个具有特定 ThreadFactory
和自定义 WorkerFactory
的 SingleThreaded Executor
@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:用于将一些参数注入 worker
@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 执行一些长时间的 运行ning 调用:
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,都不是我指定的用于工作的线程。
来自 Android 有关工人的文档:Doc
Note that CoroutineWorker.doWork() is a suspending function. Unlike Worker, this code does not run on the Executor specified in your Configuration. Instead, it defaults to Dispatchers.Default. You can customize this by providing your own CoroutineContext. In the above example, you would probably want to do this work on Dispatchers.IO, as follows:
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
并将其传递给我的工人。
我正在尝试使用 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 个具有特定 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:用于将一些参数注入 worker
@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 执行一些长时间的 运行ning 调用:
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,都不是我指定的用于工作的线程。
来自 Android 有关工人的文档:Doc
Note that CoroutineWorker.doWork() is a suspending function. Unlike Worker, this code does not run on the Executor specified in your Configuration. Instead, it defaults to Dispatchers.Default. You can customize this by providing your own CoroutineContext. In the above example, you would probably want to do this work on Dispatchers.IO, as follows:
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
并将其传递给我的工人。