Android源码阅读WorkMangaer - 6

前言

由于笔者目前水平限制,表达能力有限,尽请见谅。

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 函数获取 ListenableWorkerClass 对象,然后尝试找到一个接受 ContextWorkerParameters 为参数的构造函数,并通过该构造函数创建实例。如果反射失败,会捕获异常,记录错误,并抛出异常。
  • 然后代码尝试通过 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,则直接返回当前保存的状态。
  • 如果 currentStatenull,则调用 readSystemState()并返回这个状态。

设置 state 属性的值时,set(newState) 方法会被调用, newState 是尝试设置的新状态值

  1. 通过 synchronized(lock) 确保同一时刻只有一个线程可以更新状态。
  2. 检查新状态 newState 是否与当前状态 currentState 相同。
  3. 状态确实发生了变化,将 currentState 更新为新的状态 newState
  4. 通知所有注册的监听器关于状态变化。先将监听器集合复制到一个列表 listenersList 中,然后遍历这个列表来通知每个监听器。复制操作应该是为了避免在遍历集合时修改集合导致的异常。
  5. 使用 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的调度策略等,还是没有很理顺这些,不过先放着吧。

  • 27
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏目艾拉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值