1.WorkManager
Google发布的Android Jetpack架构中,有一个专门用于安排和管理后台任务的库WorkManager 。Android已经有很多管理后台任务的类了,比如JobScheduler、AlarmManger,或者AsyncTask、 ThreadPool。那WorkManager的优势在哪里?
①WorkManager对比JobScheduler、AlarmManger的优势:
虽然AlarmManager是一直存在,但是JobScheduler是Android 5.x之后才有的。WorkManager的底层实现,会根据你的设备API的情况,自动选用JobScheduler, 或是AlarmManager来实现后台任务。
②WorkManager对比AsyncTask、ThreadPool的优势:
WorkManager里面的任务在应用退出之后还可以继续执行。AsyncTask,、ThreadPool里面的任务在应用退出之后不会执行。
因此,WorkManager适用于那些在应用退出之后任务还需要继续执行的需求(比如应用数据上报服务器的情况),对于那些在应用退出的之后任务也需要终止的情况就需要选择ThreadPool、AsyncTask来实现了。
WorkManager是用于后台工作的架构组件,需要兼顾机会和有保证的执行。机会性执行意味着WorkManager将尽快完成您的后台工作;有保证的执行意味着即使在离开应用程序的情况下,WorkManager也会兼顾各种情况下开始逻辑工作。
①使用WorkManager API可以轻松地调度即使在应用退出或设备重启时仍应运行的可延迟异步任务。
②用统一的方法解决绝大部分后台问题。
③很容易计划、取消和管理多个工作顺序和平行的执行。
WorkManager是一个简单但非常灵活的库,它具有许多其他优点。这些包括:
①支持异步一次性和定期任务
②支持网络条件,存储空间和充电状态等约束
链接复杂的工作请求,包括并行运行工作
③一个工作请求的输出用作下一个工作的输入
④LiveData支持可轻松在UI中显示工作请求状态
使用WorkManager需要下面的gradle依赖项:
implementation "androidx.work:work-runtime:2.3.3"
整个WorkManager的执行流程:
① 给WorkManager发送工作请求WorkRequest。
② WorkManager将该请求的相关参数放入WorkManager的数据库中。
③ WorkManager根据设备版本、是否是前台任务等情况将请求操作传递给JobScheduler或者AlarmManager等部件。
④ 检查Worker是否满足约束条件,当满足约束条件时调用执行Worker。
2.WorkManager的核心类
(1)Worker
Worker是一个抽象类,这个类用来指定具体需要执行的任务。使用时要继承这个类并且实现里面的doWork()方法,在其中写具体的业务逻辑。
Worker类里面几个比较关键的函数:任务逻辑实现函数、任务输入数据的获取函数、任务输出数据的设置函数。
//任务逻辑。返回任务的执行情况:成功、失败、还是需要重新执行
@WorkerThread
public abstract Worker.Result doWork();
//任务的输入数据,有时候可能需要传递参数进去,比如下载文件需要传递文件路径进去,在doWork()函数中通过getInputData()获取到传递进来的参数
public final Data getInputData() {
return mExtras.getInputData();
}
//设置任务输出结果
public final void setOutputData(Data outputData){
mOutputData = outputData;
}
doWork()函数的返回值:
Worker.Result.SUCCESS:任务执行成功。
Worker.Result.FAILURE:任务执行失败。
Worker.Result.RETRY:任务需要重新执行,需要配合WorkRequest.Builder里面的setBackoffCriteria()函数使用。
(2)WorkRequest
WorkRequest代表一个单独的任务,是对Worker任务的包装,一个WorkRequest对应一个Worker类。可以通过WorkRequest给Worker类添加约束细节,比如指定任务应该运行的环境、任务的输入参数、任务只有在有网的情况下执行等等。WorkRequest是一个抽象类,组件里面也给了两个相应的子类:OneTimeWorkRequest(任务只执行一遍)、PeriodicWorkRequest(任务周期性的执行)。每个WorkRequest都有一个自动生成的唯一ID, 可以使用该ID来执行诸如取消排队的任务或获取任务状态等操作。
与WorkerRequest相关的有如下两个类:
① WorkRequest.Builder:用于创建WorkRequest对象的助手类 ,它有两个子类OneTimeWorkRequest.Builder和 PeriodicWorkRequest.Builder,分别对应两者创建上述两种WorkerRequest。
② Constraints:指定任务运行时的限制(例如,“仅在连接到网络时才能运行”)。使用Constraint.Builder创建Constraints,并在调用WorkRequest.Builder的build()方法之前把Constraints传给WorkRequest的setConstraints()函数。
Constraints常用函数-可以添加的限制如下:
//是否在充电状态下执行任务
public Constraints.Builder setRequiresCharging( boolean requiresCharging);
//是否在设备空闲的时候执行
public Constraints.Builder setRequiresDeviceIdle( boolean requiresDeviceIdle);
//指定网络状态执行任务。NetworkType.NOT_REQUIRED:对网络没有要求;NetworkType.CONNECTED:网络连接的时候执行;NetworkType.UNMETERED:不计费的网络比如WIFI下执行;NetworkType.NOT_ROAMING:非漫游网络状态;NetworkType.METERED:计费网络比如3G,4G下执行。
public Constraints.Builder setRequiredNetworkType(NetworkType networkType);
//在电量不足的时候是否可以执行任务
public Constraints.Builder setRequiresBatteryNotLow( boolean requiresBatteryNotLow);
//在存储容量不足时是否可以执行
public Constraints.Builder setRequiresStorageNotLow( boolean requiresStorageNotLow);
//当Uri有更新的时候是否执行任务
public Constraints.Builder addContentUriTrigger( Uri uri, boolean triggerForDescendants);
WorkRequest里有一个与重试相关的方法:
//设置任务的退避/重试策略。比如在Worker类的doWork()函数返回Result.RETRY,让该任务又重新入队。
public B setBackoffCriteria(BackoffPolicy backoffPolicy, long backoffDelay,TimeUnit timeUnit);
当任务执行失败需要重试的时候会用到这个函数,在任务执行失败的时候Worker类的doWork()函数返回Result.RETRY告诉这个任务要重试。那重试的策略就是通过setBackoffCriteria()函数来设置的。BackoffPolicy有两个值LINEAR(每次重试的时间线性增加,比如第一次10分钟,第二次就是20分钟)、EXPONENTIAL(每次重试时间指数增加)。
(3)WorkManager
管理任务请求和任务队列,需要把WorkRequest对象传给WorkManager以便将任务编入队列。通过WorkManager来调度任务,以分散系统资源的负载,同时会遵循前面设置的对任务的约束条件。
WorkManager常用函数:
//任务入队
public final void enqueue(WorkRequest... workRequests);
public abstract void enqueue(List<? extends WorkRequest> workRequests);
//链式结构的时候使用,从哪些任务开始。