布景

WorkManager 是google为Android推出Jetpack开发套件的成员之一,是一个持续化作业的引荐处理方案。 咱们在开发过程中一般会遇到一些需求持续化的操作需求,例如,上传文件到服务端,Token过期改写,定时更新服务端下发的装备等。

主要的用处是:

当即开端履行一个使命

有的使命必须当即开端履行,但这儿或许会有个疑问,为什么当即开端履行的使命不直接写代码开端履行,要利用WorkManager呢?这主要归功于WorkManager的一些特性,例如依据束缚安排使命,链式化使命等,让你代码写得更简洁,更好的扩展性。

需求长期定时运转的使命

使命需求长期定时运转的的状况,例如咱们我需求每一个小时上传一次用户日志.

推迟使命

有的使命需求延后一段时刻履行.


再持续讲解它怎么运用之前先来说说它的几个特性.

特性

束缚

供给一些束缚条件去履行使命,当束缚条件满意后才开端履行,例如,当衔接上Wifi, 当设备有满意的电量等条件

可靠性

安排的使命保证能够顺利履行,由于WorkManager内部以SqLite存储使命的履行的状况,为履行的和履行失利的都会从头测验.

加急使命

或许你会给WorkManager安排许多Task, 某些Task也许优先级比较高,需求当即履行,WorkManager供给加急的特性,能够尽早履行这类Task.

链式使命

某些Task或许需求顺序履行,也或许需求并行履行,WorkManager相同供给这类API满意需求

val continuation = WorkManager.getInstance(context)
  .beginUniqueWork(
    Constants.IMAGE_MANIPULATION_WORK_NAME,
    ExistingWorkPolicy.REPLACE,
    OneTimeWorkRequest.from(CleanupWorker::class.java)
  ).then(OneTimeWorkRequest.from(WaterColorFilterWorker::class.java))
  .then(OneTimeWorkRequest.from(GrayScaleFilterWorker::class.java))
  .then(OneTimeWorkRequest.from(BlurEffectFilterWorker::class.java))
  .then(
    if (save) {
      workRequest<SaveImageToGalleryWorker>(tag = Constants.TAG_OUTPUT)
    } else /* upload */ {
      workRequest<UploadWorker>(tag = Constants.TAG_OUTPUT)
    }
  )

线程的互操作性

无缝承继了Coroutines和RxJava的异步特性,在WorkManager也能运用这类异步的API


实战

说了这么多,下面咱们来看看怎么运用WorkManager

第一步,添加依赖

dependencies {
  def work_version = "2.8.1"
  // (Java only)
  implementation "androidx.work:work-runtime:$work_version"
  // Kotlin + coroutines
  implementation "androidx.work:work-runtime-ktx:$work_version"
  // optional - RxJava2 support
  implementation "androidx.work:work-rxjava2:$work_version"
  // optional - GCMNetworkManager support
  implementation "androidx.work:work-gcm:$work_version"
  // optional - Test helpers
  androidTestImplementation "androidx.work:work-testing:$work_version"
  // optional - Multiprocess support
  implementation "androidx.work:work-multiprocess:$work_version"
}

第二步,自界说Worker

这儿咱们需求界说,这个Task需求做什么,创立一个自界说Worker类,这儿咱们创立一个UploadWorker用于做一些后台上传的操作

class UploadWorker(appContext: Context, workerParams: WorkerParameters):
   Worker(appContext, workerParams) {
 override fun doWork(): Result {
   // 做一些上传操作
   uploadImages()
   // 代表使命履行成功
   return Result.success()
 }
}

在doWork中咱们能够写上使命需求履行的代码,当使命完毕后需求回来一个Result,这个Result有三个值

Result.success() 使命履行成功

Result.failure() 使命履行失利

Result.retry() 使命需求重试

第三步, 创立一个WorkRequest

当界说完需求做什么后咱们需求创立一个WorkRequest去发动这个使命的履行。WorkManager供给了许多灵敏的API用于界说使命的发动逻辑,例如是否履行一次仍是周期性履行,它的束缚条件是什么等。这儿演示咱们运用OneTimeWorkRequest.

val uploadWorkRequest: WorkRequest =
 OneTimeWorkRequestBuilder<UploadWorker>()
   .build()

第四步, 提交WorkRequest

当创立完成WorkRequest,咱们需求把它交给WorkManager去履行

WorkManager
  .getInstance(myContext)
  .enqueue(uploadWorkRequest)

进阶

一次性使命

创立一个简略的一次性使命

val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)

假如需求添加一些装备如束缚等能够运用builder

val uploadWorkRequest: WorkRequest =
 OneTimeWorkRequestBuilder<MyWork>()
   // 添加额外装备
   .build()
加急作业

WorkManager 履行重要的作业,同时让体系更好地控制对资源的访问。

加急作业具有以下特色:

重要性:加急作业适合对用户重要或由用户发动的使命。

速度:加急作业最适合当即开端并在几分钟内完成的短使命。

配额:束缚前台履行时刻的体系级配额决定加急作业是否能够发动。

电源办理:电源办理束缚(例如省电形式和打瞌睡形式)不太或许影响加急作业。

发动加急作业的方法也十分简略,能够直接调用setExpedited()设置该WorkRequest为一个加急使命

val request = OneTimeWorkRequestBuilder()
  .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
  .build()
WorkManager.getInstance(context)
  .enqueue(request)

这儿setExpedited会有一个参数OutOfQuotaPolicy,代表体系配额不足时分,把该使命作为一个一般使命对待.

周期性使命

咱们有一些需求例如,备份运用数据,上传日志,下载一些运用装备,需求周期性进行,咱们能够界说PeriodicWorkRequest去创立周期性的使命.


val saveRequest =
   PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
     .build()

上面这段代码每一小时履行一次使命.

可是这个时刻束缚也不是固定的,这儿界说的时刻实际上是最小距离时刻,体系会依据当时体系的状况进行恰当调整。

咱们还能够界说flexInterval让距离提早一点


val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
   1, TimeUnit.HOURS, // repeatInterval
   15, TimeUnit.MINUTES) // flexInterval
  .build()

这样咱们履行使命的时刻是repeatInterval – flexInterval,上面代码的使命会在1小时-15分钟的时分履行.

关于WorkManager需要知道的一切

周期性使命遇上束缚条件

当周期性使命遇到一些束缚条件不满意的时分将会推迟履行,直到束缚条件满意.

关于束缚

WorkManager供给了下列的一些束缚条件.

NetworkType 网络条件束缚,例如只能在衔接WIFI的状况下履行.

BatteryNotLow 非电量低束缚,在有满意的电量的时分履行.

RequiresCharging 需求充电的时分履行束缚

DeviceIdle 在设备无状况时分运转,这样不会对设备的功率产生影响.

StorageNotLow 当设备有有满意的存储空间时分运转

创立一个束缚运用Contraints.Builder()并赋值给WorkRequest.Builder().

下面代码展现创立一个束缚该使命只会在wifi并且在充电的时分履行.

val constraints = Constraints.Builder()
 .setRequiredNetworkType(NetworkType.UNMETERED)
 .setRequiresCharging(true)
 .build()
val myWorkRequest: WorkRequest =
 OneTimeWorkRequestBuilder<MyWork>()
   .setConstraints(constraints)
   .build()

推迟使命

假如你指定的使命没有束缚或者束缚已经满意,那么它会当即开端履行,假如想让它有个最少的推迟,能够指定一个最小的推迟履行时刻.

下面这个比如展现设置最小10分钟后开端加入行列.

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
 .setInitialDelay(10, TimeUnit.MINUTES)
 .build()

上面展现的针对OneTimeWorkRequestBuilder相同也适用于PeriodicWorkRequest.

退避战略

假如一个使命失利回来Result.retry(), 你的使命能够在稍等进行重试,这种退避战略能够自界说,这儿连个自界说的特点

退避推迟:退避推迟履行下次测验使命的最少时刻,一般咱们自界说最少不能低于[MIN_BACKOFF_MILLIS]

退避战略:退避战略能够指定两种一个是LINEAR(线性)和EXPONENTIAL(幂等)

实际上每一个使命都有一个默认的退避战略,缺省的退避战略是EXPONENTIAL和30s的推迟,可是你能够自界说,下面是一个自界说的比如。

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
 .setBackoffCriteria(
   BackoffPolicy.LINEAR,
   OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
   TimeUnit.MILLISECONDS)
 .build()

Tag使命

每一个使命都能够附加上一个标签,稍后能够运用这个标签找到该使命,撤销它或者检查的履行进展. 假如你有一组使命,能够添加同一个标签,能够统一的操作它们。例如运用WorkManager.cancelAllWorkByTag(String)撤销一切的使命,运用WorkManager.getWorkInfosByTag(String)回来一个使命信息列表检查当时使命的状况.

下面是一个展现给使命赋值一个标签

val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
 .addTag("cleanup")
 .build()

链式使命

WorkManager还供给了一种界说顺序履行使命或者并发履行使命的方法。

运用这种方法创立使命通过

WorkManager.beginWith(OneTimeWorkRequest)
WorkManager.beginWith(List<OneTimeWorkRequest>)

以上两个方法都会回来一个WorkContinuation.

WorkContinuation随后能够持续调用

then(OneTimeWorkRequest)
then(List<OneTimeWorkRequest>)

履行链式使命

最后能够调用enqueue()去履行你的作业链. 举个比如

WorkManager.getInstance(myContext)
 .beginWith(listOf(plantName1, plantName2, plantName3))
 .then(cache)
 .then(upload)
 .enqueue()

Input Mergers

一个父使命的履行成果能够传递给子使命,例如上面plantName1, plantName2, plantName3履行的成果能够传递

给cache使命,WorkManager运用InputMerger去办理这些多个父使命的输出成果到子使命.

这儿有两种不同类型的的InputMerger

  • OverwritingInputMerger 从输入到输出添加一切的key,遇到抵触的状况,覆盖之前的key的值

  • ArrayCreatingInputMerger 从输入到输出添加一切的key,遇到抵触的状况进行创立数组

作业链的状况

当时面的使命阻塞住的时分后边的使命相同也是阻塞状况.

关于WorkManager需要知道的一切

当时面的使命履行成功后,后边的使命才能持续开端履行

关于WorkManager需要知道的一切

当一个使命失利进行重试的时分并不会影响并发的使命

关于WorkManager需要知道的一切

一个使命失利,后边的使命也会是失利状况

关于WorkManager需要知道的一切

对于撤销也是这样

关于WorkManager需要知道的一切

结语

总的来说WorkManager是一个十分好用的组件,它处理了一些从前实现起来比较繁琐的功用,例如它的束缚履行,咱们能够等待有网络时分履行使命。咱们利用周期性履行使命功用能够很方便的履行一些诸如改写token, 定时日志上传等功用.