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

原文地址:https://www.cnblogs.com/webor2006/p/12483222.html