开发者

Android WorkManager使用以及源码分析

开发者 https://www.devze.com 2023-02-14 10:19 出处:网络 作者: 众少成多积小致巨
目录1、前言2、使用2.1、引用2.2 使用2.3 重要概念3、原理3.1 约束检测3.2 任务调度器3.3、任务流程4、总结1、前言
目录
  • 1、前言
  • 2、使用
    • 2.1、引用
    • 2.2 使用
    • 2.3 重要概念
  • 3、原理
    • 3.1 约束检测
    • 3.2 任务调度器
    • 3.3、任务流程
  • 4、总结

    1、前言

    WorkManager 是适合用于持久性工作的推荐解决方案。如果工作始终要通过应用重启和系统重新启动来调度,便是持久性的工作。由于大多数后台处理操作都是通过持久性工作完成的,因此 WorkManager 是适用于后台处理操作的主要推荐 API。 WorkManager 可处理三种类型的持久性工作:

    • 立即执行:必须立即开始且很快就完成的任务,可以加急。
    • 长时间运行:运行时间可能较长(有可能超过 10 分钟)的任务。
    • 可延期执行:延期开始并且可以定期运行的预定任务。

    2、使用

    2.1、引用

    implementation "androidx.work:work-runtime:2.7.1" //基础使用
    implementation "androidx.work:work-multiprocess:2.7.1" //跨进程时引用
    

    2.2 使用

    执行一次性任务

    Data data = new Data.Builder().putBoolean("is_test", false).build();
    WorkManager.getInstance(this).enqueue(
            new OneTimeWorkRequest.Builder(Test.class) // 执行任务一次性任务
                    .setInputMerger(NewInputMerge.class) // 输入数据合并策略,这里并没有用,链式处理时,多个上流执行结果合并,作为下流输入数据
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.MINUTES) // 重试策略
                    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) // 加急处理
                    .addTag("test").addTag("huahua") // 标识
                    .setInputData(data) // 输入数据
                    .setInitialDelay(5, TimeUnit.SECONDS) // 执行延时时间
                    .setConstraints(new Constraints.Builder().setRequiresBATteryNotLow(true).build()) // 约束,部分约束只对高版本有效
                    .build()
    );
    

    执行周期性任务

    WorkManager.getInstance(this).enqueue(
            new PeriodicWorkRequest.Builder(Test.class, 2, TimeUnit.HOURS) // 执行周期性任务,周期2小时
                    .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.MINUTES)
                    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
                    .addTag("test").addTag("huahua")
                    .setInputData(data)
                    .setInitialDelay(5, TimeUnit.SECONDS) // 首次执行延时时间
                    .setConstraints(new Constraints.Builder().setRequiresBatteryNotLow(true).build())
                    .build()
    );

    拥有名字的任务

    WorkManager.getInstance(this).enqueueUniqueWork("test", ExistingWorkPolicy.KEEP,
            new OneTimeWorkRequest.Builder(Test.class).build()); // 此种方法会对重复名字的任务进行处理
    

    监听状态

    WorkManager.getInstance(this).getWorkInfosByTagLiveData("test").observe(this, 
            new Observer<List<WorkInfo>>() {
                @Override
                public void onChanged(List<WorkInfo> workInfos) {
    
                }
            });

    定义Work代码

    public class Test extends Worker {
        public Test(@NonNull Context context, @NonNull WorkerParameters workerParams) {
            super(context, workerParams);
            Data input = getInputData(); // 获取输入数据
            boolean isTest = input.getBoolean("is_test", true);
        }
    
        @NonNull
        @Override
        public Result doWork() {
            return Result.success();
        }
    }

    继承使Worker类,实现doWork()方法,此方法是实现任务的主体;doWork()返回的 Result会通知 WorkManager 服务工作是否成功,以及工作失败时是否应重试工作。

    • Result.success():工作成功完成。
    • Result.failure():工作失败。
    • Result.retry():工作失败,应根据其重试政策在其他时间尝试。

    配置初始化 不同的版本初始化不同,但是都是通过Provider来进行的,2.6之前是WorkManagerInitializer, 2.6之后是InitializationProvider;这里按照2.7.1的版本来说,老版本有需要留言回复;有两种处理方案

    • 移除默认Provider
    • 按照Provider流程来进行

    按照提供初始化流程处理

    1.首先注意一个字符串配置:这个很重要,不建议修改

    <string name="androidx_startup" translatable="false">androidx.startup</string>
    

    2.提供实现Initializer的类,这个类是被调用的关键

    3.移除默认实现

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
        <meta-data
            android:name="androidx.work.WorkManagerInitializer"
            android:value="androidx.startup"
            tools:node="remove" /> // 这表示移除
    </provider>

    默认实现Initializer类WorkManagerInitializer,使用的默认configuration

    public final class WorkManagerInitializer implements Initializer<WorkManager> {
    
        private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");
    
        @NonNull
        @Override
        public WorkManager create(@NonNull Context context) {
            Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");
            WorkManager.initialize(context, new Configuration.Builder().build()); // 这里提供Configuration
            return WorkManager.getInstance(context);
        }
    
        @NonNull
        @Override
        public List<Class<? extends androidx.startup.Initializer<?>>> de编程客栈pendencies() {
            return Collections.emptyList(); // 提供需要执行的其它Initializer
        }
    }

    4.进行注册自定义实现; 在meta-data数据处理,key为你需要调用的初始化类,value必须为R.sting.androidx_startup这个字符串的值; 如下

    <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:node="merge" >
            <meta-data
                android:name="androidx.work.WorkManagerInitializer" // 这里为你的实现的Initializer
                android:value="androidx.startup" /> // 这里必须与R.sting.androidx_startup保持一致
        </provider>

    2.3 重要概念

    任务标识

    • id : 通过WorkRequest对象getStringId获取,每次添加一次任务,就会得到唯一的id
    • name :任务名字,暂时一次性任务才可以有; 一个任务最多一个名字,而一个名字可以对应多个任务; 同名字任务可以通过定义不同名字冲突来解决
    • tag: 一个任务可以拥有多个tag,一个tag可以对应多个任务

    任务类型

    • 一次性任务: 仅仅执行一次, 如果结果返回retry时,按照重试退避政策,进行重试,直至成功
    • 周期性任务: 按照周期执行,无论结果返回什么情况,每次周期内仅仅执行一次

    任务链

    使用 WorkManager 创建工作链并将其加入队列。工作链用于指定多个依存任务并定义这些任务的运行顺序。使用 WorkManager.beginWith(OneTimeWorkRequest 或 WorkManager.beginWith(List)返回WorkContinuation实例,然后通过其 then(OneTimeWorkRequest)或 then(List)添加任务链,最后使用WorkContinuation.enqueue()进行执行。

    任务链先添加的任务为后续任务的先决条件, 也就是前面任务成功了后面任务才会执行

    重试退避政策

    针对worker执行返回Result.retry()时处理策略, 使用方法setBackoffCriteria设置, 有两个指标,策略和延时时间(允许的最小值,即 10 秒);情况有下面2种

    • 线性LINEAR: 每次失败后重新开启任务时间延时为 延时时间次数倍(延时时间 * n)
    • EXPONENTIAL: 每次失败后重新开启任务时间延时为 延时时间的指数倍(延时时间 * 2^n)

    输入合并器

    针对一次性任务,且在工作链中,父级工作请求的输出将作为子级的输入传入的场景中使用。输入中会存在相同关键字,这时,输入就会存在冲突

    WorkManager 提供两种不同类型的 InputMerger:

    • OverwritingInputMerger:会尝试将所有输入中的所有键添加到输出中。如果发生冲突,它会覆盖先前设置的键。
    • ArrayCreatingInputMerger: 会尝试合并输入,并在必要时创建数组。

    冲突解决政策

    调度唯一工作时,发生冲突时要执行的操作。可以通过在将工作加入队列时传递一个枚举来实现此目的。

    对于一次性工作,您需要提供一个 ExistingWorkPolicy,有4 个选项。

    • REPLACE:用新工作替换现有工作。此选项将取消现有工作。
    • KEEP:保留现有工作,并忽略新工作。
    • APPEND:将新工作附加到现有工作的末尾。此政策将导致您的新工作到现有工作,在现有工作完成后运行。 现有工作将成为新工作的先决条件。如果现有工作变为 CANCELLED 或 FAILED 状态,新工作也会变为 CANCELLED 或 FAILED。如果您希望无论现有工作的状态如何都运行新工作,请改用 APPEND_OR_REPLACE
    • APPEND_OR_REPLACE: 类似于 APPEND,不过它并不依赖于先决条件工作状态。**即使现有工作变为 CANCELLED 或 FAILED 状态,新工作仍会运行。

    约束条件

    任务执行的先决条件,使用Contraints.Builder()进行构建实例。有一下约束

    • NetworkType : 约束运行工作所需的网络类型。
    • BatteryNotLow : 如果设置为 true,那么当设备处于“电量不足模式”时,工作不会运行。
    • RequiresCharging : 如果设置为 true,那么工作只能在设备充电时运行。
    • DeviceIdle:如果设置为 true,则要求用户的设备必须处于空闲状态,才能运行工作。在运行批量操作时,此约束会非常有用;若是不用此约束,批量操作可能会降低用户设备上正在积极运行的其他应用的性能。
    • StorageNotLow: 如果设置为 true,那么当用户设备上的存储空间不足时,工作不会运行。

    还有以下约束,对于>=24的版本有效:

    • setContentUriTriggers方法: 设置触发任务的uri
    • setTriggerContentUpdateDelay方法:设置触发执行的延迟时间
    • setTriggerMaxContentDelay方法:设置处罚执行的最大延时

    3、原理

    合理分为几个部分来说

    • 1. 约束检测: 约束检测的逻辑以及实现
    • 2. 任js务调度: 3种调度器, alarm、greedy、JobScheduler; 用于唤起任务执行
    • 3. 任务执行流程 :请求的包装,任务如何加入调度器,以及调度完成后执行任务详情

    这里有需要理解的一个技术点:SettableFuture,实现了ListenableFuture接口,并且增加了下面接口ListenableFuture。这个类在源码中频繁使用

    ListenableFuture只有一个方法

    void addListener(Runnable listener, Executor executor)
    

    调用了这个方法,这个类才有使用意义;调用之后,表示SettableFuture若完成,则使用executor执行listener

    另外一个让我觉得有意思的地方,或者说不同之前future的地方是, SettableFuture未实现Runnable接口,也就是其结果不是来源于自己,来源于调用下面3个方法

        public boolean set(@Nullable V value) // 正常设置结果
    
        public boolean setException(Throwable throwable) // 执行结果异常
    
    开发者_Go入门    public boolean setFuture(ListenableFuture<? extends V> future) // 设置执行结果来源,也就是ListenableFuture的执行结果
    

    3.1 约束检测

    类图如下

    Android WorkManager使用以及源码分析

    结合源码分析,结论有:

    • WorkConstraintsTracker类:使用入口,构造器传入WorkConstraintsCallback为结果回调,也可以直接调用方法areAllConstraintsMet来判断是否满足约束
    • ConstraintController类:一种约束控制器类,通过OnConstraintUpdatedCallback回调实时结果给WorkConstraintsTracker, 通过ConstraintListener与ConstraintTracker联系
    • ConstraintTracker:实际约束值的检测者,ConstraintListener回调实时传递值与ConstraintController;通过setState触发回调

    实际检测技术点,也就是ConstraintTracker实现

    3.1.1 StorageNotLowTracker类

    存储空间的是否低,根据系统广播来处理

    Intent.ACTION_DEVICE_STORAGE_OK // 存储空间够用
    Intent.ACTION_DEVICE_STORAGE_LOW // 存储空间很低
    

    初步检测状态:

    @Override
    public Boolean getInitialState() {
        Intent intent = mAppContext.registerReceiver(null, getIntentFilter());
        if (intent == null || intent.getAction() == null) {
            return true;
        } else {
            switch (intent.getAction()) {
                case Intent.ACTION_DEVICE_STORAGE_OK:
                    return true;
                case Intent.ACTION_DEVICE_STORAGE_LOW:
                    return false;
                default:
                    return null;
            }
        }
    }

    实时更新通过接收广播信息:

    public void onBroadcastReceive(Context context, @NonNull Intent intent) {
        if (intent.getAction() == null) {
            return;
        }
    
        switch (intent.getAction()) {
            case Intent.ACTION_DEVICE_STORAGE_OK:
                setState(true);
                break;
            case Intent.ACTION_DEVICE_STORAGE_LOW:
                setState(false);
                break;
        }
    }

    3.1.2 BatteryChargingTracker类

    充电状态,同样通过广播来进行处理;

    接收广播根据版本不同而不同如下:

        public IntentFilter getIntentFilter() {
            IntentFilter intentFilter = new IntentFilter();
            if (Build.VERSION.SDK_INT >= 23) {
                intentFilter.addAction(BatteryManager.ACTION_CHARGING);
                intentFilter.addAction(BatteryManager.ACTION_DISCHARGING);
            } else {
                intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
                intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
            }
            return intentFilter;
        }

    初始状态:

        @Override
        public Boolean getInitialState() {
            IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent intent = mAppContext.registerReceiver(null, intentFilter);
            if (intent == null) {
                Logger.get().error(TAG, "getInitialState - null intent received");
                return null;
            }
            return isBatteryChangedIntentCharging(intent);
        }
        
        private boolean isBatteryChangedIntentCharging(Intent intjavascriptent) {
            boolean charging;
            if (Build.VERSION.SDK_INT >= 23) {
                int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
                charging = (status == BatteryManager.BATTERY_STATUS_CHARGING
                        || status == BatteryManager.BATTERY_STATUS_FULL);
            } else {
                int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
                charging = (chargePlug != 0);
            }
            return charging;
        }

    实时状态:

    @Override
    public void onBroadcastReceive(Context context, @NonNull Intent intent) {
        String action = intent.getAction();
        if (action == null) {
            return;
        }
        Logger.get().debug(TAG, String.format("Received %s", action));
        switch (action) {
            case BatteryManager.ACTION_CHARGING:
                setState(true);
                break;
            case BatteryManager.ACTION_DISCHARGING:
                setState(false);
                break;
            case Intent.ACTION_POWER_CONNECTED:
                setState(true);
                break;
            case Intent.ACTION_POWER_DISCONNECTED:
                setState(false);
                break;
        }
    }

    3.1.3 BatteryNotLowTracker类

    电量是否低,同样通过广播实时获取状态

        Intent.ACTION_BATTERY_OKAY //电量正常
        Intent.ACTION_BATTERY_LOW //电量低
    

    初始状态:

        @Override
        public Boolean getInitialState() {
            IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
            Intent intent = mAppContext.registerReceiver(null, intentFilter);
            if (intent == null) {
                Logger.get().error(TAG, "getInitialState - null intent received");
                return null;
            }
    
            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
            int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPercentage = level / (float) scale;
    
            return (status == BatteryManager.BATTERY_STATUS_UNKNOWN
                    || batteryPercentage > BATTERY_LOW_THRESHOLD); // 这里是小于15%算是低
        }

    实时更新:

        @Override
        public void onBroadcastReceive(Context context, @NonNull Intent intent) {
            if (intent.getAction() == null) {
                return;
            }
            Logger.get().debug(TAG, String.format("Received %s", intent.getAction()));
            switch (intent.getAction()) {
                case Intent.ACTION_BATTERY_OKAY:
                    setState(true);
                    break;
                case Intent.ACTION_BATTERY_LOW:
                    setState(false);
                    break;
            }
        }

    3.1.4 NetworkStateTracker类

    网络状态,这个根据版本不同使用也不同

    • 大于等于24时, ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback networkCallback) 来进行监听网络状态变化
    • 小于24时,通过广播ConnectivityManager.CONNECTIVITY_ACTION来进行处理

    初始状态:

    NetworkState getActiveNetworkState() {
        NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
        boolean isConnected = info != null && info.isConnected();
        boolean isValidated = isActiveNetworkValidated();
        boolean isMetered = ConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager);
        boolean isNotRoaming = info != null && !info.isRoaming();
        return new NetworkState(isConnected, isValidated, isMetered, isNotRoaming);
    }          

    实时状态: 在回调NetworkCallback或者接收到广播onReceive时,调用getActiveNetworkState得到

    3.2 任务调度器

    实现Scheduler接口,调度器有3个:

    • SystemJobScheduler: 使用JobSceuler来完成任务唤起;小于23版本时使用
    • SystemAlarmScheduler: 使用Alarm来完成任务唤起;大于等于23版本使用
    • GreedyScheduler:在进程内直接调用,不同android版本均会建立 其实还有一个androidx.work.impl.background.gcm.Gcmscheduler,这个实现需要借助google的GCM推送服务来实现,这里用了反射(国内不支持),并且优先于SystemAlarmScheduler

    调度器的创建在WorkManagerImpl类

       public List<Scheduler> createSchedulers(
                @NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor taskExecutor) {
    
            return Arrays.asList(
                    Schedulers.createBestAvailableBackgroundScheduler(context, this), // 可以被系统唤起调用手段
                    new GreedyScheduler(context, configuration, taskExecutor, thisjavascript)); // 进程内调用手段
        }

    调度器被调用的逻辑在Schedulers

    public static void schedule(Configuration configuratiEkCHBEQon,WorkDatabase workDatabase,List<Scheduler> schedulers) {
            if (schedulers == null || schedulers.size() == 0) {
                return;
            }
            WorkSpecDao workSpecDao = workDatabase.workSpecDao();
            List<WorkSpec> eligibleWorkSpecsForLimitedSlots;
            List<WorkSpec> allEligibleWorkSpecs;
            workDatabase.beginTransaction();
            try {
                eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(configuration.getMaxSchedulerLimit()); 
                allEligibleWorkSpecs = workSpecDao.getAllEligibleWorkSpecsForScheduling(MAX_GREEDY_SCHEDULER_LIMIT);
    
                if (eligibleWorkSpecsForLimitedSlots != null && eligibleWorkSpecsForLimitedSlots.size() > 0) {
                    long now = System.currentTimeMillis();
                    for (WorkSpec workSpec : eligibleWorkSpecsForLimitedSlots) {
                        workSpecDao.markWorkSpecScheduled(workSpec.id, now); // 进行插槽状态处理,非默认才会被GreedyScheduler进行调度
                    }
                }
                workDatabase.setTransactionSuccessful();
            } finally {
                workDatabase.endTransaction();
            }
    
            if (eligibleWorkSpecsForLimitedSlots != null && eligibleWorkSpecsForLimitedSlots.size() > 0) {
                WorkSpec[] eligibleWorkSpecsArray =
                        new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
                eligibleWorkSpecsArray =
                        eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
                for (Scheduler scheduler : schedulers) {
                    if (scheduler.hasLimitedSchedulingSlots()) {
                        scheduler.schedule(eligibleWorkSpecsArray);
                    }
                }
            }
    
            if (allEligibleWorkSpecs != null && allEligibleWorkSpecs.size() > 0) {
                WorkSpec[] enqueuedworkSpecsArray = new WorkSpec[allEligibleWorkSpecs.size()];
                enqueuedWorkSpecsArray = allEligibleWorkSpecs.toArray(enqueuedWorkSpecsArray);
                for (Scheduler scheduler : schedulers) {
                    if (!scheduler.hasLimitedSchedulingSlots()) {
                        scheduler.schedule(enqueuedWorkSpecsArray);
                    }
                }
            }
        }

    GreedyScheduler调度器处理任务正在排队,任务最大限制是200条;其它调度器执行在排队且未被调度器处理的,且和现在调度器已经处理的总和不超过配置中的最大限制,默认是版本23是10,其它版本20

    3.2.1 GreedyScheduler调度器

    类图:

    Android WorkManager使用以及源码分析

    通过流程分析有以下结论:

    • 延时通过DelayedWorkTracker来处理,其实是通过Handler机制处理,在主Handler中进行
    • 约束通过WorkConstraintsTracker来进行检测,通过自身实现回调WorkConstraintsCallback来处理
    • 满足执行条件的任务,通过WorkManagerImpl进行执行
    • 实现ExecutionListener接口,来检测已经完成的任务,避免重复执行
    • 必须在配置的进程中处理,默认为应用主进程

    3.2.2 SystemJobScheduler调度器

    类图:

    Android WorkManager使用以及源码分析

    • SystemJobInfoConverter进行数据转换JobScheduler需要的入参,以及其它数据互相转换
    • SystemJobService负责调用WorkManagerImpl类方法去执行任务;以及任务执行完成的处理
    • 约束由JobScheduler自己内部进行;而这里只需要调用方法即可

    这个调度器比较简单,其实现主要通过了JobScheduler的实现,JobScheduler的实现原理这里不做介绍

    3.2.3 SystemAlarmScheduler调度器

    这个调度器实现就比较复杂了;类图:

    Android WorkManager使用以及源码分析

    • SystemAlarmService服务,任务各种情况通过启动此服务来处理
    • SystemAlarmDispatcher, 任务各种情况分发处理节点,并回传无任务处理情况,销毁服务
    • CommandHander具体处理各种intent事件,以及内部任务调度完成后收尾(实现了ExecutionListener接口,其意义却不是任务已经执行完成后的处理)
    • ConstraintsCommandHandler:处理了约束情况,使用WorkConstraintsTracker检测当时状态;事件是由*Proxy类广播启动service进而通知的, ConstraintProxyUpdateReceiver控制各种约束广播是否可用
    • Alarms,使用AlramManager机制处理任务延时,并启动服务
    • RescheduleReceiver:开机或者时间事件广播,重启动WorkManager处理剩余任务的;这里只有静态注册,非所有版本有效
    • DelayMetCommandHandler:进行约束实时更新判断,并在满足执行时通过WorkManagerImpl执行任务;在类图中没有表明其实现了WorkTimer.TimeLimitExceededListener(这个是对任务从调度状态到运行状态的一个控制,10分钟未完成状态变化重新处理)
    • 使用了PowerManager.WakeLock保证调度过程中cpu运行

    3.3、任务流程

    任务流程涉及调度的具体过程,在以下流程图中就会直接从Schedulers方法直接异步执行启动任务;调度过程省略;

    3.3.1 enqueue流程

    WorkManager调用时,均是先包装成WorkContinuationImpl然后调用其方法enqueue执行;

    WorkContinuationImpl: 包含了一个链表,指向了所有依赖的WorkContinuation对象;也记录了任务本身的一些信息和流程状态

    流程图

    Android WorkManager使用以及源码分析

    • WorkerWrapper:handleResult方法后续是对不同结果以及任务类别,对任务数据进行相应处理;其中进行了输入数据的合并;在执行中多个关键点对取消进行校验处理
    • WorkForegroundRunnable:启动前台服务,这个需要在实现Work中提供通知信息(方法getForegroundInfoAsync);如果有加急处理,也是启动前台服务
    • ListenableWorker中,通过setProgressAsync可以设置进度数据;成功时,doWork返回的结果中含有成功数据
    • EnqueueRunnable:enqueueWorkWithPrerequisites方法中对重复任务依据策略进行了处理
    • CancelWorkRunable:iterativelyCancelWorkAndDependents删除了依赖其的任务
    • 中间大量使用SettableFuture来让各个Runnable执行等待其执行的先决条件

    3.3.2 cancel流程

    取消时,可以通过任务的id、name、tag或者取消所有;不管是哪种调用,都是通过标识获取满足条件的任务id集合,并进行取消;其流程也只是在id集合查询时不同而已

    流程图

    Android WorkManager使用以及源码分析

    • WorkWrapper进行打断时,其流程也就是任务执行时打断处理,在执行过程中多处对打断进行了检测处理
    • 取消时,对调度、执行中的任务分别进行取消;同时同步状态到数据库

    4、总结

    上面只是大概介绍了常规使用,以及相关类图、流程,代码细节并没有展示。代码中的一些技术点需要至少会用

    • AlarmMananger
    • JobScheduler
    • 电量低、内存不足、充电状态、网络状态检测以及实时更新
    • SettableFuture
    • ......

    从代码架构上,也有需要去多思考的地方

    • 各个部分的分离抽象
    • 广播、服务组件的打开关闭、以及服务的销毁、任务执行完毕后的回调收尾等性能的考量
    • 数据库表的设计
    • 不论哪个版本,均有两个调度器去执行任务,他们有可能去处理同一个任务,这带来的复杂度处理逻辑以及优势
    • ......

    以上就是Android WorkManager使用以及源码分析的详细内容,更多关于Android WorkManager的资料请关注我们其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号