自定义 WorkManager —— 基础概念
WorkManager https://developer.android.google.cn/topic/libraries/architecture/workmanager/ Android Jetpack https://developer.android.google.cn/jetpack/
目前为止本系列已经讨论过:
在本篇文章中,我们将会讨论自定义配置相关的内容,包括:
为什么可能会需要自定义配置
如何声明自定义配置
WorkerFactory 以及自定义 WorkerFactory 的原因
DelegatingWorkerFactory 详解
Worker https://developer.android.google.cn/reference/androidx/work/Worker CoroutineWorker https://developer.android.google.cn/reference/kotlin/androidx/work/CoroutineWorker ListenableWorker https://developer.android.google.cn/reference/androidx/work/ListenableWorker WorkerFactory https://developer.android.google.cn/reference/androidx/work/WorkerFactory
默认 WorkerFactory 所创建的 Worker 只包含两个参数:
Application 的 Context
WorkerParameters
WorkerParameters https://developer.android.google.cn/reference/androidx/work/WorkerParameters
延伸阅读: 我们讲过默认的 WorkerFactory 使用反射来实例化正确的 ListenableWorker 类,但当我们的 Worker 类的类名被 R8 (或 ProGuard) 最小化之后,这个操作就会失败。为了避免这种情况,WorkManager 包含了一个 proguard-rules.pro 文件来避免您的 Worker 类的类名被混淆。
proguard-rules.pro https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:work/workmanager/proguard-rules.pro?q=workmanager%20proguard&ss=androidx
自定义配置和 WorkerFactory
2.1.0 版本中加入了一个更好的初始化 WorkManager 的方式。您可以通过在您的 Application 类中实现 WorkManager 的 Configuration.Provider 接口的方式来使用按需初始化。接下来,您只需要使用 getInstance(context) 获得实例,WorkManager 就会通过您的配置初始化它自己。
单例模式 https://en.wikipedia.org/wiki/Singleton_pattern 2.1.0 版本 (目前最新稳定版本为 2020 年 7 月 22 日发布 2.4.0 正式版) https://developer.android.google.cn/jetpack/androidx/releases/work#2.1.0-alpha01 Configuration.Provider https://developer.android.google.cn/reference/androidx/work/Configuration.Provider getInstance (context) https://developer.android.google.cn/reference/androidx/work/WorkManager#getInstance(android.content.Context)
可配置参数
如上所讲,您可以配置用来创建 Worker 的 WorkerFactory,但是您也可以自定义其他的参数。WorkManager 的 Configuration.Builder 参考指南中包含了参数的完整列表。这里我想强调两个附加参数:
Logging 级别
JobId 范围
Configuration.Builder https://developer.android.google.cn/reference/androidx/work/Configuration.Builder
文档: 调试 WorkManager https://developer.android.google.cn/topic/libraries/architecture/workmanager/how-to/debugging Advanced WorkManager codelab 实战教程 https://codelabs.developers.google.com/codelabs/android-adv-workmanager/#0 Lint 规则 https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/work/workmanager-lint/src/main/java/androidx/work/lint/SpecifyJobSchedulerIdRangeIssueDetector.kt
WorkManager 的 WorkerFactory
⚠️ 如果您在创建了一个 WorkRequest 后重构了应用,并为您的 Worker 类起了另一个名字,WorkManager 就会因为无法找到正确的类而抛出一个 ClassNotFoundException。
/* Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
class UpvoteStoryWorker(
appContext: Context,
workerParams: WorkerParameters,
private val service: UpvoteStoryHttpApi)
: CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
return try {
// 投票操作
Result.success()
} catch (e: Exception) {
if (runAttemptCount < MAX_NUMBER_OF_RETRY) {
Result.retry()
} else {
Result.failure()
}
}
}
}
Caused by java.lang.NoSuchMethodException: <init> [class android.content.Context, class androidx.work.WorkerParameters]
但是别着急,我们已经看到其中涉及的几个步骤。现在让我们回顾一下我们已经做了的事情,然后深入了解其中每一步的详细信息:
禁用默认初始化
实现一个自定义 WorkerFactory
创建自定义配置
初始化 WorkManager
禁用默认初始化
<!-- Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<application
…
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
</application>
WorkManager 的文档 https://developer.android.google.cn/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default
实现一个自定义 WorkerFactory
/* Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
class MyWorkerFactory(private val service: UpvoteStoryHttpApi) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
// 这里只能处理一个 Worker,请不要这样做!
// 参考下文来更好地使用 DelegatingWorkerFactory
return UpvoteStoryWorker(appContext, workerParameters, DesignerNewsService)
}
}
/* Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
class MyApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration =
Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.DEBUG)
.setWorkerFactory(MyWorkerFactory(DesignerNewsService))
.build()
...
}
DelegatingWorkerFactory https://developer.android.google.cn/reference/androidx/work/DelegatingWorkerFactory
使用 DelegatingWorkerFactory
addFactory() https://developer.android.google.cn/reference/androidx/work/DelegatingWorkerFactory#addFactory(androidx.work.WorkerFactory)
/* Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
class MyWorkerFactory(private val service: DesignerNewsService) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
return when(workerClassName) {
UpvoteStoryWorker::class.java.name ->
ConferenceDataWorker(appContext, workerParameters, service)
else ->
// 返回 null,这样基类就可以代理到默认的 WorkerFactory
null
}
}
}
/* Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
class MyApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration {
val myWorkerFactory = DelegatingWorkingFactory()
myWorkerFactory.addFactory(MyWorkerFactory(service))
// 在这里添加您应用中可能会使用的其他 WorkerFactory
return Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.setWorkerFactory(myWorkerFactory)
.build()
}
...
}
总结
推荐阅读