探究Google力推的JetPack库<五>---------WorkManager
作用:
对于Jetpack架构库只剩下最后一个木有学啦:
这次来搞定它,先上官网了解一下它:
那啥场景会有这种任务需求呢?官网也举例说明了:
而它不适合使用的场景官网也给出了提示:
它还有一个特点就是:自动选择合适的方式执行任务,以减少电量消耗。另外它向前兼容的Android版本为:
基本使用:
创建一个任务:
先添加依赖:
接下来则定义一个任务:
package com.android.workmanager; import android.util.Log; import androidx.annotation.NonNull; import androidx.work.Data; import androidx.work.Worker; public class MainWorker extends Worker { //这个方法是在子线程执行的 @NonNull @Override public Result doWork() { //上传,下载,同步数据。。。。。。 Log.i("cexo", "MainWorker work执行了"); //获取mainActivity传入进来的数据 String data = getInputData().getString("cexo"); Log.i("cexo", "MainWorker work中取到了数据" + data); //把任务中的数据回传到activity中 Data outputData = new Data.Builder().putString("name", "cexo").build(); setOutputData(outputData); return Result.SUCCESS; } }
配置、执行任务:
定义单次执行任务:
单任务执行:
这种任务就只是执行一次的,具体如何定义呢?
然后开始执行:
运行看一下:
现在任务中已经接收到了我们调用传的数据了,那调用的地方怎么来接收任务里面回传的数据呢?
package com.android.workmanager; import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.Observer; import androidx.work.Data; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; import androidx.work.WorkStatus; public class MainActivity extends AppCompatActivity { //定义一个单次执行的任务 OneTimeWorkRequest request; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //OneTimeorkRequest的初始化 //定义传入到任务中的数据 Data inputData = new Data.Builder().putString("cexo", "cexo的数据").build(); request = new OneTimeWorkRequest.Builder(MainWorker.class) .setInputData(inputData) .build(); //把任务加入到任务队列中,并在满足某种条件的情况去执行 //接收任务中回来的数据 WorkManager.getInstance().getStatusById(request.getId()) .observe(this, new Observer<WorkStatus>() { @Override public void onChanged(WorkStatus workStatus) { if (workStatus != null && workStatus.getState().isFinished()) { //在任务执行完成后 Log.i("cexo", "activity取到了任务回传的数据" + workStatus.getOutputData().getString("name")); } } }); WorkManager.getInstance().enqueue(request); } }
运行:
任务链方式执行:
也就是可以可以添加多个任务,将其以一个链式的方式进行调用,下面咱们多定义几个Worker试一下:
每个Worker的代码都很简单,这里只看其中一个既可:
package com.android.workmanager; import android.util.Log; import androidx.annotation.NonNull; import androidx.work.Worker; public class MainWorker2 extends Worker { //这个方法是在子线程执行的 @NonNull @Override public Result doWork() { //上传,下载,同步数据。。。。。。 Log.i("cexo", "work2执行了"); return Result.SUCCESS; } }
然后再对应进行相关的任务配置:
接下来则可以对以上多个任务进行一些规则的控制,下面举几个规则:
顺序执行:
运行:
则就按照咱们定义的顺序来进行输出了~~挺不错的,多个任务的管理细节我们完全不用管,只要定义规则既可。
分支执行:
看一下运行结果:
也有可能是:
也就是3和2顺序不定,但是4肯定是在3和2之后执行。
多任务链方式:
任务链与任务链之间也可以进行控制,相当的强大,下面试一下:
任务的唯一性:
对于WorkContinuation,它还有一个唯一任务的配置方式,不过目前我没找到何时用它,官方也没出它的一个场景DEMO,先了解一下吧:
这块在实际工作中遇到了再来体会它的作用。
定义重复执行任务:
这种任务可以重复进行执行的,具体语法如下:
其中最小的间隔时间是要等15分钟。。所以也没法演示了:
原理剖析:
不带条件:
目前咱们的使用木有带任何触发条件的,而触发条件的设定在下面再来进行学习,先来看一下目前这块的实现原理:
咱们就从我们调用的角度来分析:
也就是WorkManager是一个抽象类,其具体实现类为WorkManagerImpl,然后跟进去:
而这个对像的初始化是在:
WorkManagerImpl()构造:
看一下整个构造细节:
1.创建数据库,create中使用的是Room。
2.任务线程池的创建。
3.创建Processor。
4.检查应用程序强制停止Checks for app force stops。
相当于是一种容错,比如是否要强制停止,是否要重新再调度任务。
enqueue():
而它是一个接口:
其中它有三种调度器:
而目前的调度器是GreedyScheduler:
所以跟进去看一下如何调度的:
其中mExecutor则为线程池:
而WorkerWrapper是一个线程:
开始执行线程了:
至此整个调度任务的主流程就分析完了,其中可以看到底层做了很多的状态处理,还用到的room对数据进行保存。
带条件:
在上面分析代码时有个带条件的分支木有分析:
那下面咱们来定义一下约束,看约束是干嘛的?
具体效果就不试了,接下来看一下这些约束是怎么实现的,其实是通过监听广播来实现的:
/* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.work.impl.background.systemalarm; import static androidx.work.NetworkType.NOT_REQUIRED; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import androidx.work.Constraints; import androidx.work.Logger; import androidx.work.impl.model.WorkSpec; import java.util.List; abstract class ConstraintProxy extends BroadcastReceiver { private static final String TAG = "ConstraintProxy"; @Override public void onReceive(Context context, Intent intent) { Logger.debug(TAG, String.format("onReceive : %s", intent)); Intent constraintChangedIntent = CommandHandler.createConstraintsChangedIntent(context); context.startService(constraintChangedIntent); } /** * Proxy for Battery Not Low constraint */ public static class BatteryNotLowProxy extends ConstraintProxy { } /** * Proxy for Battery Charging constraint */ public static class BatteryChargingProxy extends ConstraintProxy { } /** * Proxy for Storage Not Low constraint */ public static class StorageNotLowProxy extends ConstraintProxy { } /** * Proxy for Network State constraints */ public static class NetworkStateProxy extends ConstraintProxy { } /** * Enables/Disables proxies based on constraints in {@link WorkSpec}s * * @param context {@link Context} * @param workSpecs list of {@link WorkSpec}s to update proxies against */ static void updateAll(Context context, List<WorkSpec> workSpecs) { boolean batteryNotLowProxyEnabled = false; boolean batteryChargingProxyEnabled = false; boolean storageNotLowProxyEnabled = false; boolean networkStateProxyEnabled = false; for (WorkSpec workSpec : workSpecs) { Constraints constraints = workSpec.constraints; batteryNotLowProxyEnabled |= constraints.requiresBatteryNotLow(); batteryChargingProxyEnabled |= constraints.requiresCharging(); storageNotLowProxyEnabled |= constraints.requiresStorageNotLow(); networkStateProxyEnabled |= constraints.getRequiredNetworkType() != NOT_REQUIRED; if (batteryNotLowProxyEnabled && batteryChargingProxyEnabled && storageNotLowProxyEnabled && networkStateProxyEnabled) { break; } } Intent updateProxyIntent = ConstraintProxyUpdateReceiver.newConstraintProxyUpdateIntent( batteryNotLowProxyEnabled, batteryChargingProxyEnabled, storageNotLowProxyEnabled, networkStateProxyEnabled); // ConstraintProxies are being updated via a separate broadcast receiver. // For more information on why we do this look at b/73549299 context.sendBroadcast(updateProxyIntent); } }
而它有以下几个子类:
当收到广播之后,则会启动一个服务:
为啥是它,因为之前接收到广播时创建Intent就是这个类型:
继续往下分析:
最终消息处理又会回到这来了:
而如果还有约束条件:
总结:
如果木有约束条件的Worker的执行是通过线程最终反射来执行我们的doWork()方法的;而如果有约束条件最终会监听相关的广播,然后进行广播的一些处理,处理完了最终再来执行原来的doWork()流程了。
至此关于JetPack架构方面的库就整体学了一遍,算是一个入门吧,毕境还没有真实到项目中用起来,这块未来打算用Jetpack技术来用项目对它进行操练一下,只有这样才算是掌握。