AAC---WorkManager

WorkManager介绍

它的主要作用则是管理在后台工作的任务,即使APP没有启动,它也能保证任务可以被执行。这样的好处可以提高应用的效率 , 降低耗电量 , 同时通过约束的方式来限制功能的上传。

WorkManager机制

在5.0以上的版本WorkManager会通过JobScheduler或者Firebase的JobDispatcher来实现,而在5.0以下的版本,则会通过AlarmManager来实现

它有以下好处:

  1. 支持异步的单次、定时的任务
  2. 支持网络条件、存储空间、充电状态等条件的约束
  3. 支持复杂的并行的链式任务
  4. 某个Work Request的输出作为下一个Work Request的输入
  5. 仅支持Target 14以上的API
  6. 遵循系统的健康
  7. 支持LiveData将请求的状态同步到UI

但是WorkManager仍然无法代替线程池、AsyncTask,例如以下的例子都可以使用WorkManager:上传日志,实现图片的滤镜并且保存图片,定期从网络同步本地数据。

使用WorkManager

  1. 导入WorkManager
    在app的Module中导入Kotlin的WorkManager。而目前的版本号已经到了1.0.0-alpha13
dependencies {
    implementation "android.arch.work:work-runtime-ktx:$versions.work"
}
  1. 创建Worker
    创建一个类,继承自Worker,并且实现doWork函数,返回任务执行的结果,并且在任务中可以携带数据返回结果 , 而任务结果可以在LiveData中获取。
class TestWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
    private val TAG by lazy { TestWorker::class.java.simpleName }
    private val KEY_EXCEPTION by lazy { "KEY_EXCEPTION" }
    private val KEY_SUCCESS by lazy { "KEY_SUCCESS" }
    override fun doWork(): Result {
        return try {
            Log.e(TAG, "Worker Do Work")
            val successData = Data.Builder().putString(KEY_SUCCESS, "Success").build()
            Result.success(successData)
        } catch (exception: Exception) {
            val exceptionData = Data.Builder().putString(KEY_EXCEPTION, "Exception :${exception.message}").build()
            Result.failure(exceptionData)
        }
    }
}
  1. 将Worker加入队列中
    在创建完任务后,需要将该任务加入WorkManager的队列中。在以下代码中,创建了只执行一次的任务OneTimeWorkRequest,并且携带了输入的参数setInputData,创建完后,就可以将它插入到WorkManager的队列中等待执行。
val inputData = Data.Builder().putString("KEY_INPUT", "input data").build()
val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java).setInputData(inputData).build()
WorkManager.getInstance().enqueue(workRequest)

通过PeriodicWorkRequest创建的任务,是会定期执行的,需要传入定期的时间即可

创建链式任务

当某些任务具有依赖关系时候(如A依赖B完成的结果,B又依赖C完成的结果),则需要使用链式任务。


链式任务

可以通过WorkManager.beginWith来开始执行任务,并且通过then来将后续的任务链接上。并且可以将前一个任务的输出作为后一个任务的输入。

val workA = OneTimeWorkRequest.Builder(TestWorker::class.java).build()
val workB = OneTimeWorkRequest.Builder(BlurWorker::class.java).build()
val workC = OneTimeWorkRequest.Builder(CleanupWorker::class.java).build()
WorkManager.getInstance().beginWith(workA).then(workB).then(workC).enqueue()

doWork中通过getInputData来获取上一个任务传递的参数

class BlurWork extends Worker {

        public BlurWork@NonNull Context context, @NonNull WorkerParameters workerParams) {
            super(context, workerParams);
        }

        @NonNull
        @Override
        public ListenableWorker.Result doWork() {
            getInputData().getKeyValueMap().get("Key");
            return Result.success();
        }
    }

如果只允许单独的任务存在的话,则需要通过beginUniqueWork来开启任务。当存在重复的任务时,会采用传入的ExistingWorkPolicy来对已存在的任务进行策略处理。

WorkManager.getInstance().beginUniqueWork("workName",ExistingWorkPolicy.REPLACE,workA).enqueue()

多链式任务

例如有任务需要等待多个链式任务完成的话 , 则可以通过WorkManager来实现.

多个链式任务

通过以下方式来完成链式任务的执行.

WorkContinuation chain1 = WorkManager.getInstance(myContext)
        .beginWith(workA)
        .then(workB);
    WorkContinuation chain2 = WorkManager.getInstance(myContext)
        .beginWith(workC)
        .then(workD);
    WorkContinuation chain3 = WorkContinuation
        .combine(Arrays.asList(chain1, chain2))
        .then(workE);
    chain3.enqueue();
    

使用LiveData监听任务状态

在任务执行的过程中,可以通过LiveData来监听任务的状态,所有的任务都具有这几种状态:

  • BLOCKED:阻塞
  • CANCELLED:被取消
  • ENQUEUED:入队列
  • FAILED:失败
  • RUNNING:正在运行
  • SUCCEEDED:运行成功
  1. 通过addTag设置任务的Tag
val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java).addTag("workRequest").build()
WorkManager.getInstance().enqueue(workRequest)
  1. 1.0.0-alpha10版本中,还可以通过WorkManager.getInstance().getStatusesByTagLiveData()获取对应的Worker的Status。

1.0.0-alpha13版本中,已经没有该函数了,已经替换成getWorkInfosByTagLiveData,而获取的也就是WorkInfo,也差不多。

val liveData = WorkManager.getInstance().getWorkInfosByTagLiveData("workRequest");
liveData.observe(this, Observer {
     if (it[0].state.isFinished) {
      // 任务已经完成
     } else {
      // 任务未完成
     }
})

而获取任务结果的话 , 可以通过

 WorkManager.getInstance(getContext()).getWorkInfoByIdLiveData(uuid)
.observe(getOwnerActivity(), new Observer() {
            @Override
            public void onChanged(WorkInfo workInfo) {
                // 获取任务执行结果
                workInfo.getOutputData();
            }
        });

取消任务

在WorkManager中也可以取消:

// 根据TAG取消所有任务
WorkManager.getInstance().cancelAllWorkByTag()
// 根据UniqueWorkName取消任务
WorkManager.getInstance().cancelUniqueWork()
// 根据uuid取消任务
WorkManager.getInstance().cancelWorkById()

增加任务约束

当某个任务需要在某个条件时开始,可以在任务的Builder中添加约束(Constraint)。

// 创建正在充电的约束
val constraints = Constraints.Builder()
        .setRequiresCharging(true)
        .build()

//  将约束添加到请求中
val save = OneTimeWorkRequestBuilder()
        .setConstraints(constraints)
        .addTag(TAG_OUTPUT)
        .build()
continuation = continuation.then(save)

// 启动任务
continuation.enqueue()

新增加进度同步

在最新的2.3.4版本的WorkManager中新增任务进度同步的接口.

public class ProgressWorker extends Worker {

        private static final String PROGRESS = "PROGRESS";
        private static final long DELAY = 1000L;

        public ProgressWorker(
            @NonNull Context context,
            @NonNull WorkerParameters parameters) {
            super(context, parameters);
            // 设置初始化进度为0
            setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());
        }

        @NonNull
        @Override
        public Result doWork() {
             //Do something
            ...
            // 设置进度为100
            setProgressAsync(new Data.Builder().putInt(PROGRESS, 100).build());
            return Result.success();
        }
    }

LiveData中获取到该进度

WorkManager.getInstance(getApplicationContext())
         // requestId is the WorkRequest id
         .getWorkInfoByIdLiveData(requestId)
         .observe(lifecycleOwner, new Observer() {
                 @Override
                 public void onChanged(@Nullable WorkInfo workInfo) {
                     if (workInfo != null) {
                         Data progress = workInfo.getInt(PROGRESS, 0)
                         // Do something with progress
                 }
          }
});

你可能感兴趣的:(AAC---WorkManager)