前言
由于笔者目前水平限制,表达能力有限,尽请见谅。
WorkManager 是 Android Jetpack 库的一部分,提供了一种向后兼容的方式来安排可延迟的异步任务,这些任务即使在应用退出或设备重启后也应该继续执行,它是 Android 推荐的解决方案,用于处理需要保证执行的后台任务。WorkManager 适合用于那些不需要立即执行的任务,但最终需要完成的任务。
上文主要深挖到了两大调度器的调度原理,接下来先将继续深入。
正文
WokerFactory
用途
WorkerFactory
允许开发者自定义工作实例(Worker
实例)的创建过程。使用 WorkerFactory
,开发者可以在工作执行时注入依赖项、实现复杂的构造逻辑,或者基于运行时条件选择不同类型的工作实现。
假设有一个需要依赖注入的 Worker
类:
class MyWorker(
context: Context,
workerParams: WorkerParameters,
private val myDependency: MyDependency
) : Worker(context, workerParams) {
override fun doWork(): Result {
// 使用依赖完成工作...
return Result.success()
}
}
创建一个自定义 WorkerFactory
来处理 MyWorker
的实例化,并注入所需的依赖:
class MyWorkerFactory(private val myDependency: MyDependency) : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker? {
return when (workerClassName) {
MyWorker::class.java.name ->
MyWorker(appContext, workerParameters, myDependency)
else -> null // 对于其他的 Worker 类,返回 null 让 WorkManager 使用默认逻辑
}
}
}
接下来在应用启动时配置 WorkManager 使用自定义 WorkerFactory:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 创建依赖实例
val myDependency = MyDependency()
// 配置 WorkManager
val config = Configuration.Builder()
.setWorkerFactory(MyWorkerFactory(myDependency))
.build()
// 初始化 WorkManager
WorkManager.initialize(this, config)
}
}
自定义 WorkerFactory
允许在工作实例创建时注入依赖项,对于使用 Dagger 或其他依赖注入框架的项目非常有用。
同时自定义WorkerFactory
可以基于运行时条件(如用户偏好设置、设备类型等)动态选择或配置工作实例。
接下来就深入WorkFactory的源码
如下抽象方法四个参数的含义如下:
appContext: Context
正常Android中常接触的context对象
workerClassName: String
要创建的 Worker
类的完全限定名(包括包名的类名),WorkerFactory
可以通过这个类名决定如何和何时创建 Worker
的实例。这个机制允许 WorkerFactory
支持多种类型的 Worker
,并且根据类名动态地实例化它们。
workerParameters: WorkerParameters
包含了执行工作所需的所有参数和配置。这些参数可能包括工作的输入数据、工作的唯一标识符、延迟执行工作的持续时间、重试策略等。
defaultWorkerFactory源码如下:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
object DefaultWorkerFactory : WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
) = null
}
关键源码createWorkerWithDefaultFallback如下:
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun createWorkerWithDefaultFallback(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker {
fun getWorkerClass(workerClassName: String): Class<out ListenableWorker> {
return try {
Class.forName(workerClassName).asSubclass(ListenableWorker::class.java)
} catch (throwable: Throwable) {
Logger.get().error(TAG, "Invalid class: $workerClassName", throwable)
throw throwable
}
}
fun fallbackToReflection(
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker {
val clazz = getWorkerClass(workerClassName)
return try {
val constructor = clazz.getDeclaredConstructor(
Context::class.java, WorkerParameters::class.java
)
constructor.newInstance(appContext, workerParameters)
} catch (e: Throwable) {
Logger.get().error(TAG, "Could not instantiate $workerClassName", e)
throw e
}
}
val worker = createWorker(appContext, workerClassName, workerParameters)
?: fallbackToReflection(workerClassName, workerParameters)
if (worker.isUsed) {
val message = "WorkerFactory (${javaClass.name}) returned an instance of" +
" a ListenableWorker ($workerClassName) which has already been invoked. " +
"createWorker() must always return a new instance of a ListenableWorker."
throw IllegalStateException(message)
}
return worker
}
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)限制
仅允许在库的内部(即 WorkManager 库本身)使用。
getWorkerClass
是一个局部函数,用于通过反射获取与workerClassName
参数对应的Class
对象。如果类名有效,这个函数会返回该类的Class
对象;如果无效,会捕获异常,记录错误日志,并将异常抛出。fallbackToReflection
也是一个局部函数,当createWorker
方法返回null
时调用,使用反射来创建ListenableWorker
实例。首先通过getWorkerClass
函数获取ListenableWorker
的Class
对象,然后尝试找到一个接受Context
和WorkerParameters
为参数的构造函数,并通过该构造函数创建实例。如果反射失败,会捕获异常,记录错误,并抛出异常。- 然后代码尝试通过
createWorker
方法创建实例。如果createWorker
返回null
,则调用fallbackToReflection
方法通过反射创建实例。 - 一旦创建了
ListenableWorker
实例,代码会检查isUsed
属性,确保返回的实例是新创建的并且之前没有被使用过。如果检测到实例已经被使用,会抛出IllegalStateException
,因为每个ListenableWorker
实例都应该是新创建的并且在创建后尚未执行任何工作。 - 最后如果实例成功创建并通过了
isUsed
的检查,方法会返回这个ListenableWorker
实例。
综上,两者关系如下:
createWorker
是一个抽象方法,需要开发者重写来实现自定义的 ListenableWorker
创建逻辑。这个方法让开发者完全自由度来决定如何根据工作类名和参数创建工作实例,,该方法返回 ListenableWorker?
类型的对象,允许返回 null
。如果开发者的实现返回了 null
,表明自定义工厂无法创建该工作实例。
工厂方法和回退策略结合:createWorker
提供了自定义创建工作实例的接口,而 createWorkerWithDefaultFallback
确保了这一过程的稳健性和可靠性。
ConstriantTracker
当工作请求添加到 WorkManager 时,会根据需要的约束条件注册相应的 ConstraintTracker
监听器,ConstraintTracker
将跟踪系统约束的状态变化。
这是一个抽象类
构造参数、属性有如下:
泛型 <T>
:不同的 ConstraintTracker
子类可以用来跟踪不同类型的系统约束状态。
context: Context
:上下文,可用于访问系统服务。taskExecutor: TaskExecutor
:一般用于执行异步任务。appContext: Context
:应用程序级的上下文。currentState: T?
:当前的约束状态。listeners: LinkedHashSet<ConstraintListener<T>>()
:一个包含所有已注册监听器的集合。
关键函数有如下:
添加一个监听器,如果添加的是第一个监听器,将触发状态读取和开始跟踪函数。
移除一个监听器,如果后面没有监听器,跟踪停止。
fun addListener(listener: ConstraintListener<T>) {
synchronized(lock) {
if (listeners.add(listener)) {
if (listeners.size == 1) {
currentState = readSystemState()
Logger.get().debug(
TAG, "${javaClass.simpleName}: initial state = $currentState"
)
startTracking()
}
@Suppress("UNCHECKED_CAST")
listener.onConstraintChanged(currentState as T)
}
}
}
fun removeListener(listener: ConstraintListener<T>) {
synchronized(lock) {
if (listeners.remove(listener) && listeners.isEmpty()) {
stopTracking()
}
}
}
代码还定义了一个state
属性,负责管理和通知约束状态的变化。
get()
方法检查 currentState
是否为 null
:
- 如果
currentState
不为null
,则直接返回当前保存的状态。 - 如果
currentState
为null
,则调用readSystemState()
并返回这个状态。
设置 state
属性的值时,set(newState)
方法会被调用, newState
是尝试设置的新状态值
- 通过
synchronized(lock)
确保同一时刻只有一个线程可以更新状态。 - 检查新状态
newState
是否与当前状态currentState
相同。 - 状态确实发生了变化,将
currentState
更新为新的状态newState
。 - 通知所有注册的监听器关于状态变化。先将监听器集合复制到一个列表
listenersList
中,然后遍历这个列表来通知每个监听器。复制操作应该是为了避免在遍历集合时修改集合导致的异常。 - 使用
taskExecutor.mainThreadExecutor.execute { ... }
确保监听器的onConstraintChanged
方法在主线程上被调用。
var state: T
get() {
return currentState ?: readSystemState()
}
set(newState) {
synchronized(lock) {
if (currentState != null && (currentState == newState)) {
return
}
currentState = newState
// onConstraintChanged may lead to calls to addListener or removeListener.
// This can potentially result in a modification to the set while it is being
// iterated over, so we handle this by creating a copy and using that for
// iteration.
val listenersList = listeners.toList()
taskExecutor.mainThreadExecutor.execute {
listenersList.forEach { listener ->
// currentState was initialized by now
@Suppress("UNCHECKED_CAST")
listener.onConstraintChanged(currentState as T)
}
}
}
}
抽象方法如下,需要时被重写。
/**
* Reads the state of the constraints from source of truth. (e.g. NetworkManager for
* NetworkTracker). It is always accurate unlike `state` that can be stale after stopTracking
* call.
*/
abstract fun readSystemState(): T
/**
* Start tracking for constraint state changes.
*/
abstract fun startTracking()
/**
* Stop tracking for constraint state changes.
*/
abstract fun stopTracking()
WorkManager系列的源码阅读应该会到此结束了,每次阅读源码都觉得是个很累的过程,尤其是WorkManager的源码,本身十分庞大,笔者的6篇文章也只是探索了笔者认为的主要部分,但还是有很多地方没有探索,比如存储WorkSepc的数据库,相关Dao,JobScehdule的调度策略等,还是没有很理顺这些,不过先放着吧。