WorkManager
WorkManager是Google最新的后台任务调度解决方案,Google计划2020年11月1日开始全面统一在Android上使用WorkManager处理后台任务的调度处理工作
在后台,WorkManager根据以下条件使用基础的作业调度服务:
WorkManager的优势
- 最高向后兼容到 API 14
- 在运行 API 23 及以上级别的设备上使用 JobScheduler
- 在运行 API 14-22 的设备上结合使用 BroadcastReceiver 和 AlarmManager
- 添加网络可用性或充电状态等工作约束,根据添加的约束条件智能的启动后台任务
- 调度一次性或周期性异步任务
- 监控和管理计划任务
- 将任务链接起来,可以给多个任务进行串行、并行调度,甚至多个链多个链的串行并行
- 确保任务执行,即使应用或设备重启也同样执行任务,依赖于room的持久化实现
- 遵循低电耗模式等省电功能,更省电
现在,WorkManager库已经成熟,并且极大的减轻了Android开发的工作量,还更加省电、可靠、性能优越
但是要注意WorkManager适用于及时性不高的任务,一些高及时性的场景不要使用,比如你的订单创建那就要立马发送请求,及时响应结果
假如说你的订单是离线(也就是没有网络)也需要创建成功,等网络再进行提交,那么这种场景就比较适合使用WorkManager,能极大减少工作量 ,还能一定程度上保证订单不会丢失
之所以WorkManager能进程退出、奔溃、重启机器
情况下也能保证完成提交给系统的延时任务是依赖与数据的持久化
以后要是吹WorkManager源码分析、底层实现分析的牛逼
主要就拿JobScheduler、JobService、sqlite(room)、sp、GreedyScheduler、BroadcastReceiver、Alarm、线程池、Handler、LifecycleService(Androidx)吹
围观一下数据库
使用
使用比较简单,首先添加必要的依赖注册初始化
//依赖库
def work_version = "2.3.0-alpha01"
implementation "androidx.work:work-runtime:$work_version"
//清单文件
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:directBootAware="false"
android:exported="false"
android:multiprocess="true"
tools:node="remove"
tools:targetApi="n" />
//application
public class Myapplication extends Application implements Configuration.Provider {
@Override
public void onCreate() {
super.onCreate();
Configuration myConfig = new Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.VERBOSE)
.build();
WorkManager.initialize(getBaseContext(), myConfig);
}
@NonNull
@Override
public Configuration getWorkManagerConfiguration() {
return new Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.build();
}
}
如果不在manifest文件注册application中初始化,可能会报以下错
WorkManager is not initialized properly. You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider
WorkManager is already initialized. Did you try to initialize it manually without disabling WorkManagerInitializer? See WorkManager#initialize(Context, Configuration) or the class levelJavadoc for more information.
另外要注意:
WorkManager.getInstance()
调用不要在application
中的attachBaseContext
方法调用
对于老项目要使用的话,首先要对项目进行迁移androidX,Android studio已经可以一键迁移,修改buildToolsVersion 28以上、gradle3.2以上
classpath 'com.android.tools.build:gradle:3.2.0+'
android.useAndroidX=true
android.enableJetifier=true
剩下的代码基本分为三步
1、创建
2、设置约束条件
3、执行
当然 中间可以观察者模式调用,观察调用进度、数据,也可以暂停、取消操作
下面看看代码使用WorkManager
创建WorkRequest 并将其加入队列
-
一次性任务 OneTimeWorkRequest
执行工作器的确切时间还取决于 WorkRequest 中使用的Constraints约束和系统优化。WorkManager 经过设计,在满足这些约束的情况下提供可能的最佳行为
//任务约束条件
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)//联网状态
.setRequiresBatteryNotLow(true)//非低电量
.setRequiresDeviceIdle(true)//设备空闲
.setRequiresStorageNotLow(true)//存储空间足够
.setRequiresCharging(true)//充电状态
.setTriggerContentMaxDelay(20, TimeUnit.DAYS)//延时20天后执行
.build();
//定义传入到任务中的数据
Data inputData = new Data.Builder().putString("chris", "数据").build();
//一次性任务
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker.class)
.setInputData(inputData)
.setConstraints(constraints)
.build();
-
重复周期性任务 PeriodicWorkRequest
最小周期不能低于15分钟,如果设置小于15分钟,也是按15分钟的周期运行
日志会打印:Interval duration lesser than minimum allowed value; Changed to 900000"
//一天一次周期任务
PeriodicWorkRequest saveRequest =
new PeriodicWorkRequest.Builder(MainWorker.class, 1, TimeUnit.DAYS)
.setConstraints(constraints)
.build();
- woker任务执行
public class MainWorker extends Worker {
private static final String TAG = "MainWorker";
public MainWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
//这个方法是在子线程执行的
@NonNull
@Override
public Result doWork() {
//上传,下载,同步数据
Log.e(TAG, "执行了");
//获取mainActivity传入进来的数据
String data = getInputData().getString("chris");
Log.e(TAG, "中取到了数据" + data);
//把任务中的数据回传到activity中
Data outputData = new Data.Builder().putString("name", "chris").build();
//进度
setProgressAsync(new Data.Builder().putInt("Progress",78).build());
return Result.success(outputData);
}
}
- 加入队列执行
WorkManager.getInstance()
.beginUniqueWork("unique",
ExistingWorkPolicy.REPLACE//设置任务不重复
, request)
.enqueue();
- 观察工作状态接收数据
//接收任务中回来的数据、进度
WorkManager.getInstance().getWorkInfoByIdLiveData(request.getId())
.observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(WorkInfo workInfo) {
//获取进度
Data progress = workInfo.getProgress();
int Progress = progress.getInt("Progress", 0);
//获取数据
String name = workInfo.getOutputData().getString("name");
Log.i(TAG, "取到了任务回传的数据" + name);
}
});
- 任务的取消、暂停
//取消所有
WorkManager.getInstance(this).cancelAllWork();
//取消某一个 如saveRequest
WorkManager.getInstance().cancelWorkById(saveRequest.getId());
//按标记取消 WorkRequest会取消所有具有此标记的工作
WorkManager.getInstance().cancelAllWorkByTag(request.getStringId());
//取消所有未完成的工作的工作链的名字:unique
WorkManager.getInstance(this).cancelUniqueWork("unique");
有高级玩法,比如取消当前的执行任务并将其 REPLACE 为新工作链
- 任务链
多任务组合一个任务链
WorkManager.getInstance(this)
//request,request2并发执行
.beginWith(Arrays.asList(request, request2))
//request1 request2顺序执行
.then(request1).then(request2)
.then(Arrays.asList(request1, request2))
.enqueue();
多任务链合并一个任务链
//两个任务链
WorkContinuation begin = WorkManager.getInstance(this).beginWith(Arrays.asList(request, request2));
WorkContinuation then = WorkManager.getInstance(this).beginWith(request).then(request1);
//多任务链合并,
WorkContinuation thenEnd = WorkContinuation.combine(Arrays.asList(begin, then)).then(request);
//多任务链执行
thenEnd.enqueue();
如果需要创建一个唯一单次工作链可以使用 WorkManager.beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest 代替 beginWith()
//创建一个唯一周期重复工作链 WorkManager.getInstance(base).enqueueUniquePeriodicWork(TAG_Unique, ExistingPeriodicWorkPolicy.REPLACE, mPeriodicWorkRequest);
adb 查看自己app的work
adb shell am broadcast -a "androidx.work.diagnostics.REQUEST_DIAGNOSTICS" appPackageName
执行adb广播之后,logcat过滤自己app的日志显示所有