JetPack源码分析之WorkManager原理(二)

253 阅读3分钟

在上一篇文章大致说了一下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 这个标识