在上一篇文章大致说了一下WorkManager 的简单使用,并且从 ContentProvider 启动说了一下 WorkManager 的初始化,今天这篇文章就根据主线流程来继续分析一下这个过程
首先我们来分析一下 WorkManagerImpl 初始化的角色
private void internalInit(@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor workTaskExecutor,
@NonNull WorkDatabase workDatabase,
@NonNull List<Scheduler> schedulers,
@NonNull Processor processor) {
context = context.getApplicationContext();
mContext = context;
mConfiguration = configuration;
mWorkTaskExecutor = workTaskExecutor;
mWorkDatabase = workDatabase;
mSchedulers = schedulers;
mProcessor = processor;
mPreferenceUtils = new PreferenceUtils(workDatabase);
mForceStopRunnableCompleted = false;
// Check for direct boot mode
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.isDeviceProtectedStorage()) {
throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");
}
// Checks for app force stops.
mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
}
从这个方法可以看出来,在 WorkManagerImpl 的初始化方法需要注意的的参数
1:workTaskExecutor 线程池
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
从线程池的创建方法可以看到,这个线程池是一个只有主要线程,并且任务个数没有限制
2:mWorkDatabase Room数据库 任务创建后就会将任务添加到Room数据库,这个里面有几个非常重要参数 id tag name,都是用来标识任务来用的, 他们关联的几个方法如下
WorkManager.getInstance(this).getWorkInfosForUniqueWorkLiveData("").observe(this){
}
WorkManager.getInstance(this).getWorkInfoByIdLiveData(_id).observe(this){
}
WorkManager.getInstance(this).getWorkInfosByTagLiveData("").observe(this){
}
创建任务也是大致如下
WorkManager.getInstance(this).enqueueUniquePeriodicWork("tsmTag1",ExistingPeriodicWorkPolicy.REPLACE,oneTimeWorkRequest)
在任务的创建过程中也可以给任务设置tag,用来给任务添加标记
var oneTimeWorkRequest= PeriodicWorkRequestBuilder<TsmWork1>(15,TimeUnit.MINUTES)
.setConstraints(constraints)//设置约束条件
.setInputData(dataInput)
.addTag("")
// .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
// 加急策略,没有加急配额,加急任务回退成普通任务,也可以将任务丢弃
.build()
3:mSchedulers 调度者
public List<Scheduler> createSchedulers(
@NonNull Context context,
@NonNull Configuration configuration,
@NonNull TaskExecutor taskExecutor) {
return Arrays.asList(
Schedulers.createBestAvailableBackgroundScheduler(context, this),
// Specify the task executor directly here as this happens before internalInit.
// GreedyScheduler creates ConstraintTrackers and controllers eagerly.
new GreedyScheduler(context, configuration, taskExecutor, this));
}
在创建 mSchedulers 的时候会添加两个调度者,第一个是 SystemJobScheduler
public SystemJobScheduler(@NonNull Context context, @NonNull WorkManagerImpl workManager) {
this(context,
workManager,
(JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE),
new SystemJobInfoConverter(context));
}
从他的初始化方法中可以看到 (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE) 这个service ,那么他是用来干什么的呢, 这个Serivce 是android 5.0 中新增的,用来在未来某个时间段当预设的条件满足时,会执行这个任务, WorkManager 的约束条件就是用它来实现的,具体的实现方法大家可以自行搜索一下,由于他的内容介绍还是非常多的,这里就不介绍那么多了,但关于他的使用还是非常有必要学习一下的,
第二个调度者就是 GreedyScheduler 贪婪调度器
4:mProcessor 处理器 用来调度任务和指定任务执行的管理者
分析完 WorkManagerImpl 的初始化角色,我们接下来继续分析 enqueue 这个动作,
其实不管是 enqueue 还是 enqueue 一个list 或者是 enqueueUnique 系列的方法,都是创建创建一个 WorkContinuationImpl 并且调用他的 enqueue 这个方法,我们来继续分析一下 new WorkContinuationImpl 这个动作
public WorkContinuationImpl(@NonNull WorkManagerImpl workManagerImpl,
@Nullable String name,
@NonNull ExistingWorkPolicy existingWorkPolicy,
@NonNull List<? extends WorkRequest> work,
@Nullable List<WorkContinuationImpl> parents) {
mWorkManagerImpl = workManagerImpl;
mName = name;
mExistingWorkPolicy = existingWorkPolicy;
mWork = work;
mParents = parents;
mIds = new ArrayList<>(mWork.size());
mAllIds = new ArrayList<>();
if (parents != null) {
for (WorkContinuationImpl parent : parents) {
mAllIds.addAll(parent.mAllIds);
}
}
for (int i = 0; i < work.size(); i++) {
String id = work.get(i).getStringId();
mIds.add(id);
mAllIds.add(id);
}
}
在他的构造方法中,只有一个属性需要说明,那就是 ExistingWorkPolicy existingWorkPolicy , 他的含义就是代表相同的任务如果存在,接下来的执行策略是什么 KEEP or REPLACE or APPEND or APPEND_OR_REPLACE 根据字面的意思就是 保持 替换 衔接 衔接或者替换 ,比较难理解的是第三个 APPEND 他的意思就是添加新的任务时,新的任务将作为该任务的子任务被加入,但是如果原始任务的状态是取消或者失败的时候,该子任务也会被标题相同的状态,如果不想被标记为取消或者失败,可以使用 APPEND_OR_REPLACE 这个标识