WorkManager是Android Jetpack的一个强大的组件,用于处理后台耗时任务。后台任务可以是一次性的,也可以是重复的。
在使用前先把库导进来,其中前两个是必选项。
dependencies {
def work_version = "2.7.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"
}
WorkManager使用非常简单,就是定义任务,设置请求,提交即可。我们先来定义一个后台任务。
任务类继承自Worker类,在doWork里完成耗时任务。
public class SensorWorker extends Worker {
private String TAG = "SensorWorker";
public SensorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
Log.d(TAG, "work begin");
try {
//模拟后台耗时任务
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(Math.random() < 0.5){
//任务出现异常,返回failure
Log.d(TAG, "work failed");
return Result.failure();
}
//任务完成,返回success
Log.d(TAG, "work succeed");
return Result.success();
}
}
接着设置一个任务请求,这里使用了建造者模式,也就是说我们是可以通过Builder来做更多具体的设定的。
WorkRequest request = new OneTimeWorkRequest.Builder(SensorWorker.class)
.build();
如果希望任务延迟30分钟再执行,则代码如下。
WorkRequest request = new OneTimeWorkRequest.Builder(SensorWorker.class)
.setInitialDelay(30, TimeUnit.MINUTES)
.build();
最后提交请求即可,使用起来跟Retrofit和Glide非常像。
WorkManager.getInstance(this)
.enqueue(request);
我们并不能保证任务每次都一定完成,对于任务异常,可以选择直接返回failure或者重新执行任务。下面来看看重试的代码。
public class SensorWorker extends Worker {
...
@NonNull
@Override
public Result doWork() {
Log.d(TAG, "work begin");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(Math.random() < 0.5){
//任务异常,重试
return Result.retry();
}
return Result.success();
}
}
接着配置一下重试的策略,下面规定任务异常后20秒后才重试。WorkManager规定最短间隔时间为10秒。
重试策略有两种。当然,重试的间隔时间并不是精确的,毕竟Android不是实时操作系统。
重试策略 | 解释 |
---|---|
BackoffPolicy.LINEAR | 重试间隔保持不变 |
BackoffPolicy.EXPONENTIAL | 每次重试间隔是上一次的2倍 |
WorkRequest request = new OneTimeWorkRequest.Builder(SensorWorker.class)
.setBackoffCriteria(BackoffPolicy.LINEAR,20, TimeUnit.SECONDS)
.build();
WorkManager还支持执行周期性的任务。使用方法如下。最小间隔时间是15分钟。
WorkRequest request = new PeriodicWorkRequest.Builder(SensorWorker.class,1,TimeUnit.HOURS)
.build();
或者
WorkRequest request2 = new PeriodicWorkRequest.Builder(SensorWorker.class,1,TimeUnit.HOURS,15,TimeUnit.MINUTES)
.build();
后台任务种类繁多,有的会消耗流量、有的非常耗电。对于后台任务WorkManager也有一些约束它们的方法。
Constraints类可以通过建造者模式来设置需要的限定条件,常用的限制条件如下。
方法 | 解释 |
---|---|
setRequiredNetworkType | 设置任务执行的网络类型 |
setRequiresCharging | 是否需要在充电下执行 |
setRequiresBatteryNotLow | 是否需要在非低电量下执行 |
setRequiresStorageNotLow | 是否需要在磁盘充足时执行 |
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build();
WorkRequest request = new OneTimeWorkRequest.Builder(SensorWorker.class)
.setConstraints(constraints)
.build();
WorkManager提供了一些取消任务的方法。需要注意的是WorkManager只能取消周期性任务,单次任务是无法取消的。测试方法如下。
public class MainActivity extends AppCompatActivity {
private Button button;
private UUID mTaskId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过Id来取消任务
WorkManager.getInstance(MainActivity.this)
.cancelWorkById(mTaskId);
}
});
//注意,WorkManager只能取消周期性任务
WorkRequest request = new PeriodicWorkRequest.Builder(SensorWorker.class,30,TimeUnit.MINUTES)
.build();
//获取任务的Id
mTaskId = request.getId();
WorkManager.getInstance(this)
.enqueue(request);
}
}
我们还可以给任务添加监听器,这样一来就可以在不同任务状态下更新相应的UI了,代码如下。onChanged方法是在主线程下调用的,所以可以直接刷新UI。
//添加任务监听
WorkManager.getInstance(MainActivity.this).getWorkInfoByIdLiveData(mTaskId).observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(WorkInfo workInfo) {
if(workInfo.getState() != null && workInfo.getState() == WorkInfo.State.SUCCEEDED){
Toast.makeText(MainActivity.this, "finished", Toast.LENGTH_SHORT).show();
}
}
});
本篇文章讲解了Jetpack的处理后台任务的强大组件WorkManager。
《WorkManager (3) —— 取消和监听任务》
《Android 开发者文档》