前言

总结和学习 Android WorkManager 的相关用法。

WorkManager 有什么特殊之处

在日常开发中,有些使命需求在异步线程履行,并且这些作业耗时较长,经过普通的子线程或后台服务无法胜任时,就需求 WorkManager 了。

WorkManager 适用于需求牢靠运转的作业,即便用户导航脱离屏幕、退出运用或重启设备也不影响作业的履行。例如:

  • 后端服务发送日志或剖析数据。
  • 定时将运用数据与服务器同步。 WorkManager 不适用于那些可在运用进程结束时安全停止的进程内后台作业。

它也并非对所有需求立即履行的作业都适用的通用解决方案

牢靠运转 这个特色太有诱惑力了,尤其是关于周期性的作业。比较经过诸如1像素的 Activity、进程保活、互相保活/拉起之类的方法来履行特定的作业,运用官方提供的 WorkManager 能够避免做一些十分 hack 的作业,正所谓事半功倍。

WorkManager 的功用

比较传统的 AsyncTask/Coroutine/RxJava/Executors ,WorkManager 有更明显的特色。

  • 结合系统特性的束缚: 能够结合设备当时的网络、电量等情况,束缚使命履行的条件。比如等到用户连接 WiFi 后进行 App 的更新,电量足够的时候进行系统更新,条件不满足就等候,都能够经过 WorkManager 内置的 API 十分方便的完结。

  • 强大的调度: 经过 WorkManager 履行的作业,会由系统经过 SQLite 数据库进行办理,而上层开发者能够依据作业的标记进行状态监控、撤销等操作。

  • 作业链和灵活的重试战略: 这一点娴熟运用 RxJava 的同学应该十分喜爱。将多个作业经过合理的编排进行串联并联,依据作业履行的结果进行重试,WorkManager 都支持。

一起 WorkManager 能够与 Coroutine 及 RxJava 无缝联接。

这儿需求理解的是,WorkManager 不是用来替代 Coroutine 或其他能够履行异步操作结构的,而是依据这些结构的特色提供了更强大的功用,是互补的关系,一些经过 Coroutine 就能够完结的作业,就不要强行往 WorkManager 上套了,不要为了用而用,许多时候适宜就足够了。

WorkManager 入门

关于运用 WorkManager 怎么增加依赖及 demo 等级的的运用场景,能够直接参阅 WorkManager 运用入门 ,十分简略。

Android WorkManager 初探

从官方提供的作业类型,能够看到主要有两类作业,即一次性和周期性的,望文生义一个是履行一次就完事,一类是周期性重复履行的作业。

下面就经过一个简略的示例,从一次性作业(在 WorkManager 中,能够多履行多个使命,规范期间一个使命被界说为一个 Work,这儿索性就称为作业)开始,了解一下具体怎么运用 WorkManager.

  1. 界说目标

一个删去文件的使命,接连多次调用,掩盖履行。删去使命履行时,传入的路劲参数异常或文件不存在时回来失利,正常删去则回来成功。

  1. 创立 Work
    class CleanWork(appContext: Context, workerParameters: WorkerParameters) :
        Worker(appContext, workerParameters) {
        override fun doWork(): Result {
            val path = inputData.getString("path")
            return if (TextUtils.isEmpty(path)) {
                Result.failure(Data.Builder().putString("result", "filepath is null").build())
            } else {
                if (cleanOutDateFile(path!!)) {
                    Result.success()
                } else {
                    Result.failure(Data.Builder().putString("result", "file not exist").build())
                }
            }
        }
    }

这儿重视以下几点 :

  • 继承抽象类 Worker 界说自己的 Worker ,完结 doWork 办法。
  • 回来参数 Result 有三个类型
    • Result.success():作业成功完结。
    • Result.failure():作业失利。
    • Result.retry():作业失利,应依据其重试政策在其他时刻尝试。
  • Work 入参和结果的传递
    • 经过 inputData 的 getXXX 办法,能够获取调用使命时传入的参数
    • 经过 Result 回来结果是参入的 Data 参数,能够回来具体的结果,不传的话,就相当于 void 类型的函数。

简略看一下 cleanOutDateFile 的界说

    private fun cleanOutDateFile(path: String): Boolean {
        val file = File(path)
        return if (file.exists()) {
            file.delete()
            true
        } else {
            false
        }
    }
  1. 创立 WorkRequest 并参加行列
    fun clean(context: Context, path: String) {
        val request =
            OneTimeWorkRequestBuilder<CleanWork>()
                .addTag("cleanWork")
                .setInputData(workDataOf("path" to path)).build()
        WorkManager.getInstance(context)
            .enqueueUniqueWork("clean", ExistingWorkPolicy.REPLACE, request)
    }

这儿重视以下几点 :

  • OneTimeWorkRequestBuilder 的泛型参数便是上面自界说的 Work
  • 经过 addTag 能够给当时要履行的 Work 增加仅有标识,这样能够依据这个 tag 获取 Work 履行的结果,或许撤销 Work
  • setInputData 传入 Data 对象,即可给 Work 传参,这儿的参数类型其实便是 Map,因而能够传递各种类型的值,确保 key 和 Work 中对应即可。
  • WorkRequest 参加行列时,能够简略调用 enqueue 办法,这样如果有重复的 WorkRequest 发生抵触,默认会采取保留现有 Work ,抛弃新 WorkRequest 。或许像这儿相同调用 enqueueUniqueWork,经过界说 tag ,自行制定面临抵触情况的战略。
  1. 调用并观察 Work 履行情况
class WorkManagerViewModel(app: Application) : AndroidViewModel(app) {
    private val workManager = WorkManager.getInstance(app)
    val cleanWorkInfo = workManager.getWorkInfosByTagLiveData("cleanWork")
}
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        workManagerViewModel.cleanWorkInfo.observe(this@FilterActivity) {
            Log.i("cleanWork", "info -> $it")
            if (it != null && it.size > 0) {
                val work = it[it.size - 1]
                Log.i("cleanWork", "$work")
            val out = work.outputData.getString("result")
                Log.i("cleanWork", "$out")               
            }
        }
        val path = cacheDir.absolutePath + File.separator + "current.txt"
        WorkUtil.clean(it.context, path)
    }

这儿接连调用两次 clean 办法之后看日志


20:23:16.391 17128-17128 cleanWork                           I  info -> [WorkInfo{mId='d64379e8-17b5-484d-9c2f-2273c1fd629f', mState=SUCCEEDED, mOutputData=Data
                                                                                                    {}, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}]
20:23:16.391 17128-17128 cleanWork                           I  WorkInfo{mId='d64379e8-17b5-484d-9c2f-2273c1fd629f', mState=SUCCEEDED, mOutputData=Data
                                                                                                    {}, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}
20:23:16.391 17128-17128 cleanWork                           I  null
20:25:07.611 17128-17128 cleanWork                           I  info -> [WorkInfo{mId='b238f68c-b1c8-4994-975b-7f5d2b67d10c', mState=FAILED, mOutputData=Data {result : file not
                                                                                                    exist, }, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}]
20:25:07.611 17128-17128 cleanWork                           I  WorkInfo{mId='b238f68c-b1c8-4994-975b-7f5d2b67d10c', mState=FAILED, mOutputData=Data {result : file not
                                                                                                    exist, }, mTags=[cleanWork, com.engineer.android.mini.jetpack.work.WorkUtil$CleanWork], mProgress=Data {}}
20:25:07.611 17128-17128 cleanWork                           I  file not exist

能够看到,第一次履行成功后,再次进行 clean 操作时就回来了 file not exist 的错误信息,而整个行列里也只要一条 WorkInfo,说明设置的 ExistingWorkPolicy.REPLACE 的战略也生效了。

这儿经过这个简略的示例能够看到,WorkManager 十分强大,并且其 API 的界说十分友爱,参数和办法命名很恰当,经过称号就能够知道要办法或参数的意义。

小结

WorkManager 最大的特色是其履行的是耐久化的使命。这点咱们经过 Android Studio Inspection 功用就能够看到,他经过 SQLite 数据库从不同维度存储了各种刺进到行列中 Worker 的信息。

Android WorkManager 初探

因而,在界说 Worker ,创立 WorkRequest 和挑选 Worker 增加到行列中的方法是都要谨慎,因为这些信息都会被存储。一起,咱们也能够经过 Inspection 东西检查当时进程中存在的 Worker 信息,进行问题的排查和了解。

参阅文档