zoukankan      html  css  js  c++  java
  • 探究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技术来用项目对它进行操练一下,只有这样才算是掌握。

  • 相关阅读:
    CF140C New Year Snowmen
    CF1131G Most Dangerous Shark
    莫比乌斯函数&欧拉函数&筛法 综合运用
    【51nod1220】约数之和
    题解[CF1228E Another Filling the Grid]
    dsu on tree学习笔记
    线性基学习笔记
    题解[CF895C Square Subsets]
    博弈论学习笔记
    题解[ [JSOI2007]文本生成器 ]
  • 原文地址:https://www.cnblogs.com/webor2006/p/12483222.html
Copyright © 2011-2022 走看看