jetpack–WorkManager 源码简析

前言

Jetpack 提供了 WorkManager来执行一些任务,既然执行任务,就涉及到任务的创建、任务的属性、任务的执行条件、如何执行任务等等。本文通过任务属性、任务约束及如何执行任务来揭开workmanager的神秘面纱

一、任务创建(任务属性)

//任务定义
class UploadWorker(conText: Context, params: WorkerParameters) : Worker(conText, params) {

    override fun doWork(): Result {
        var name = inputData.getString("name")
        Log.d("UploadWorker ==" ,"dowork 执行了 "+name)
        //Toast.makeText(applicationContext, "执行requestManager", Toast.LENGTH_LONG).show()
        return Result.retry() //Result.failure()  Result.retry()
    }
}


复制代码
可以看到 UploadWorker 继承了Worker,而Worker 又继承了 ListenableWorker,传入参数有两个 一个是上下文,一个是 WorkerParameters
public abstract class Worker extends ListenableWorker {

    // Package-private to avoid synthetic accessor.
    SettableFuture<Result> mFuture;

    @Keep
    @SuppressLint("BanKeepAnnotation")
    public Worker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @WorkerThread
    public abstract @NonNull Result doWork();

    //startWork方法 在线程池中调用执行 doWork 方法,然后将doWork方法的返回值设置到Future中返回
    @Override
    public final @NonNull ListenableFuture<Result> startWork() {
        mFuture = SettableFuture.create();
        getBackgroundExecutor().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Result result = doWork();
                    mFuture.set(result);
                } catch (Throwable throwable) {
                    mFuture.setException(throwable);
                }

            }
        });
        return mFuture;
    }
}
复制代码

Worker 的代码也很简单,暴露了 doWork()方法让子类实现,然后 提供了 startWork 方法,用线程池执行dowork,然后将返回值放到SettableFuture 中。

//ListenableWorker
public abstract class ListenableWorker {
    //上下文
    private @NonNull Context mAppContext;
    //传入参数
    private @NonNull WorkerParameters mWorkerParams;
    //是否暂停
    private volatile boolean mStopped;
    //是否被使用
    private boolean mUsed;
    //是否运行在前台
    private boolean mRunInForeground;
    //构造函数 context 和 WorkerParameters 都不能为空,为空时会抛异常
    public ListenableWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
        // Actually make sure we don't get nulls.
        if (appContext == null) {
            throw new IllegalArgumentException("Application Context is null");
        }

        if (workerParams == null) {
            throw new IllegalArgumentException("WorkerParameters is null");
        }

        mAppContext = appContext;
        mWorkerParams = workerParams;
    }
    
    public final @NonNull Context getApplicationContext() {
        return mAppContext;
    }

    public final @NonNull UUID getId() {
        return mWorkerParams.getId();
    }

    public final @NonNull Data getInputData() {
        return mWorkerParams.getInputData();
    }

    public final @NonNull Set<String> getTags() {
        return mWorkerParams.getTags();
    }

    @RequiresApi(24)
    public final @NonNull List<Uri> getTriggeredContentUris() {
        return mWorkerParams.getTriggeredContentUris();
    }

    @RequiresApi(24)
    public final @NonNull List<String> getTriggeredContentAuthorities() {
        return mWorkerParams.getTriggeredContentAuthorities();
    }

    @RequiresApi(28)
    public final @Nullable Network getNetwork() {
        return mWorkerParams.getNetwork();
    }

    @IntRange(from = 0)
    public final int getRunAttemptCount() {
        return mWorkerParams.getRunAttemptCount();
    }
    
    //startWork方法  Woker类实现,这里标注了 调用需要是mainThread 
    @MainThread
    public abstract @NonNull ListenableFuture<Result> startWork();

    //更新执行进度
    @NonNull
    public final ListenableFuture<Void> setProgressAsync(@NonNull Data data) {
        return mWorkerParams.getProgressUpdater()
                .updateProgress(getApplicationContext(), getId(), data);
    }

    
    @NonNull
    public final ListenableFuture<Void> setForegroundAsync(@NonNull ForegroundInfo foregroundInfo) {
        mRunInForeground = true;
        return mWorkerParams.getForegroundUpdater()
                .setForegroundAsync(getApplicationContext(), getId(), foregroundInfo);
    }
    //暂停相关操作
    public final boolean isStopped() {
        return mStopped;
    }
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public final void stop() {
        mStopped = true;
        onStopped();
    }

    public void onStopped() {
        // Do nothing by default.
    }

    //是否已经被使用
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public final boolean isUsed() {
        return mUsed;
    }
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public final void setUsed() {
        mUsed = true;
    }
    
    //是否在前台运行
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public boolean isRunInForeground() {
        return mRunInForeground;
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull Executor getBackgroundExecutor() {
        return mWorkerParams.getBackgroundExecutor();
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull TaskExecutor getTaskExecutor() {
        return mWorkerParams.getTaskExecutor();
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public @NonNull WorkerFactory getWorkerFactory() {
        return mWorkerParams.getWorkerFactory();
    }
    //执行结果类 result/Success/Failure/Retry
    public abstract static class Result {
       
        @NonNull
        public static Result success() {
            return new Success();
        }

        @NonNull
        public static Result success(@NonNull Data outputData) {
            return new Success(outputData);
        }

        @NonNull
        public static Result retry() {
            return new Retry();
        }

        @NonNull
        public static Result failure() {
            return new Failure();
        }

        @NonNull
        public static Result failure(@NonNull Data outputData) {
            return new Failure(outputData);
        }

        /**
         * @hide
         */
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        Result() {
            // Restricting access to the constructor, to give Result a sealed class
            // like behavior.
        }

        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public static final class Success extends Result {
            private final Data mOutputData;

            public Success() {
                this(Data.EMPTY);
            }

            public Success(@NonNull Data outputData) {
                super();
                mOutputData = outputData;
            }

            /**
             * @hide
             */
            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            public @NonNull Data getOutputData() {
                return mOutputData;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;

                Success success = (Success) o;

                return mOutputData.equals(success.mOutputData);
            }

            @Override
            public int hashCode() {
                String name = Success.class.getName();
                return 31 * name.hashCode() + mOutputData.hashCode();
            }

            @Override
            public String toString() {
                return "Success {" + "mOutputData=" + mOutputData + '}';
            }
        }
      
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public static final class Failure extends Result {
            private final Data mOutputData;

            public Failure() {
                this(Data.EMPTY);
            }

            public Failure(@NonNull Data outputData) {
                super();
                mOutputData = outputData;
            }

            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            public @NonNull Data getOutputData() {
                return mOutputData;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;

                Failure failure = (Failure) o;

                return mOutputData.equals(failure.mOutputData);
            }

            @Override
            public int hashCode() {
                String name = Failure.class.getName();
                return 31 * name.hashCode() + mOutputData.hashCode();
            }

            @Override
            public String toString() {
                return "Failure {" +  "mOutputData=" + mOutputData +  '}';
            }
        }

        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public static final class Retry extends Result {
            public Retry() {
                super();
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                // We are treating all instances of Retry as equivalent.
                return o != null && getClass() == o.getClass();
            }

            @Override
            public int hashCode() {
                String name = Retry.class.getName();
                return name.hashCode();
            }

            @Override
            public String toString() {
                return "Retry";
            }
        }
    }
}

//任务相关参数
public final class WorkerParameters {

    private @NonNull UUID mId;   //随机序列
    private @NonNull Data mInputData;//输入参数
    private @NonNull Set<String> mTags;//任务TAG
    private @NonNull RuntimeExtras mRuntimeExtras; //执行时参数
    private int mRunAttemptCount;  //执行重试次数
    private @NonNull Executor mBackgroundExecutor;  //后台任务执行线程池
    private @NonNull TaskExecutor mWorkTaskExecutor; //任务执行线程池
    private @NonNull WorkerFactory mWorkerFactory; //任务工厂
    private @NonNull ProgressUpdater mProgressUpdater;//进度更新者
    private @NonNull ForegroundUpdater mForegroundUpdater;//前台更新者
}
复制代码

小结:

任务参数:WorkerParameters 定义了一系列任务相关参数,包括执行任务的入参mInputData,任务标识TAG,任务执行线程池,任务进度更新,任务工厂等

任务结果:(Result/Success/Failure/Retry)

二、任务执行条件(任务约束 )

我们执行任务有一系列约束条件,并且字段都带上了 @ColumnInfo注释,意味着会写进数据库

a.网络条件约束有以下几种:
public enum NetworkType {
    //任务对网络无要求
    NOT_REQUIRED,
    //只要有网络连接 就可以执行任务
    CONNECTED,
    //非计量网络链接 可以执行任务
    UNMETERED,
    //非漫游网络连接 可以执行任务
    NOT_ROAMING,
    //计量网络连接 可以执行任务
    METERED
}

//网络条件判断
public class NetworkStateTracker extends ConstraintTracker<NetworkState> {

    // Synthetic Accessor
    static final String TAG = Logger.tagWithPrefix("NetworkStateTracker");

    private final ConnectivityManager mConnectivityManager;

    @RequiresApi(24)
    private NetworkStateCallback mNetworkCallback;
    private NetworkStateBroadcastReceiver mBroadcastReceiver;

    public NetworkStateTracker(@NonNull Context context, @NonNull TaskExecutor taskExecutor) {
        super(context, taskExecutor);
        mConnectivityManager =
                (ConnectivityManager) mAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        //判断如果支持NetworkCallback就用NetWorkCallback 监听网络连接
        //否则用广播
        if (isNetworkCallbackSupported()) {
            mNetworkCallback = new NetworkStateCallback();
        } else {
            mBroadcastReceiver = new NetworkStateBroadcastReceiver();
        }
    }

    @Override
    public NetworkState getInitialState() {
        return getActiveNetworkState();
    }

    @Override
    public void startTracking() {
        if (isNetworkCallbackSupported()) {
            try {
                Logger.get().debug(TAG, "Registering network callback");
                mConnectivityManager.registerDefaultNetworkCallback(mNetworkCallback);
            } catch (IllegalArgumentException | SecurityException e) {
            }
        } else {
            Logger.get().debug(TAG, "Registering broadcast receiver");
            mAppContext.registerReceiver(mBroadcastReceiver,
                    new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        }
    }

    @Override
    public void stopTracking() {
        if (isNetworkCallbackSupported()) {
            try {
                Logger.get().debug(TAG, "Unregistering network callback");
                mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
            } catch (IllegalArgumentException | SecurityException e) {
               
            }
        } else {
            Logger.get().debug(TAG, "Unregistering broadcast receiver");
            mAppContext.unregisterReceiver(mBroadcastReceiver);
        }
    }
   //判断是否支持 NetworkCallback  API 版本 >=24
    private static boolean isNetworkCallbackSupported() {
        // Based on requiring ConnectivityManager#registerDefaultNetworkCallback - added in API 24.
        return Build.VERSION.SDK_INT >= 24;
    }

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    NetworkState getActiveNetworkState() {
        // Use getActiveNetworkInfo() instead of getNetworkInfo(network) because it can detect VPNs.
        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);
    }
    //判断网络是否合法
    private boolean isActiveNetworkValidated() {
        if (Build.VERSION.SDK_INT < 23) {
            return false; // NET_CAPABILITY_VALIDATED not available until API 23. Used on API 26+.
        }
        Network network = mConnectivityManager.getActiveNetwork();
        NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(network);
        return capabilities != null
                && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
    }

    @RequiresApi(24)
    private class NetworkStateCallback extends NetworkCallback {
        NetworkStateCallback() {
        }

        @Override
        public void onCapabilitiesChanged(
                @NonNull Network network, @NonNull NetworkCapabilities capabilities) {
            setState(getActiveNetworkState());
        }

        @Override
        public void onLost(@NonNull Network network) {
            setState(getActiveNetworkState());
        }
    }

    private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
        NetworkStateBroadcastReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null || intent.getAction() == null) {
                return;
            }
            if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                Logger.get().debug(TAG, "Network broadcast received");
                setState(getActiveNetworkState());
            }
        }
    }
}

复制代码
网络连接的判断在API>=24 时采用 NetworkStateCallback 来监听网络连接状态的变更,在api < 24时采用BroadcastReceiver 来监听系统广播CONNECTIVITY_ACTION 来监听网络连接状态的变更,变更后会同步更新网络的计量、漫游、连接状态等
b.充电约束
public class BatteryChargingTracker extends BroadcastReceiverConstraintTracker<Boolean> {

    private static final String TAG = Logger.tagWithPrefix("BatteryChrgTracker");

    /**
     * Create an instance of {@link BatteryChargingTracker}.
     * @param context The application {@link Context}
     * @param taskExecutor The internal {@link TaskExecutor} being used by WorkManager.
     */
    public BatteryChargingTracker(@NonNull Context context, @NonNull TaskExecutor taskExecutor) {
        super(context, taskExecutor);
    }
    //获取初始状态是否在充电
    @Override
    public Boolean getInitialState() {
        // {@link ACTION_CHARGING} and {@link ACTION_DISCHARGING} are not sticky broadcasts, so
        // we use {@link ACTION_BATTERY_CHANGED} on all APIs to get the initial state.
        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);
    }

    @Override
    public IntentFilter getIntentFilter() {
        IntentFilter intentFilter = new IntentFilter();
        //23 版本及以上监听 ACTION_CHARGING 和  ACTION_DISCHARGING
        //23 版本以下监听 ACTION_POWER_CONNECTED 和 ACTION_POWER_DISCONNECTED
        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 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;
        }
    }
    //判断是否在充电
    private boolean isBatteryChangedIntentCharging(Intent intent) {
        boolean charging;
        //23版本及以上获取 BatteryManager.EXTRA_STATUS 来判断
        //23以下获取BatteryManager.EXTRA_PLUGGED 来判断
        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;
    }
}
复制代码
设备是否在充电状态的判断以api23 为界限,23 以下通过监听广播ACTION_POWER_CONNECTED 和 ACTION_POWER_DISCONNECTED 来判断充电和断电,23及以上通过监听 ACTION_CHARGING 和 ACTION_DISCHARGING 来判断充电状态
c.设备是否空闲约束

值的注意的是 这个约束条件并没有找到监听的方案,并且有诸多限制,比如API>=23;前台任务不能设置这个条件;设置过setBackoffCriteria 的任务不能使用此条件

d.设备内存约束
public class StorageNotLowTracker extends BroadcastReceiverConstraintTracker<Boolean> {

    private static final String TAG = Logger.tagWithPrefix("StorageNotLowTracker");
    public StorageNotLowTracker(@NonNull Context context, @NonNull TaskExecutor taskExecutor) {
        super(context, taskExecutor);
    }

    @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;
            }
        }
    }

    @Override
    public IntentFilter getIntentFilter() {
        // In API 26+, DEVICE_STORAGE_OK/LOW are deprecated and are no longer sent to
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
        return intentFilter;
    }

    @Override
    public void onBroadcastReceive(Context context, @NonNull Intent intent) {
        if (intent.getAction() == null) {
            return; // Should never happen since the IntentFilter was configured.
        }

        Logger.get().debug(TAG, String.format("Received %s", intent.getAction()));

        switch (intent.getAction()) {
            case Intent.ACTION_DEVICE_STORAGE_OK:
                setState(true);
                break;

            case Intent.ACTION_DEVICE_STORAGE_LOW:
                setState(false);
                break;
        }
    }
}
复制代码
可以看到代码逻辑也很简单,也是通过监听广播ACTION_DEVICE_STORAGE_OK 和 ACTION_DEVICE_STORAGE_LOW 来决定设备存储这个约束条件;但是在 >api26 版本这两个广播已经废弃了,且未来可能不再发送这两个广播,所以这个条件使用的话要谨慎
e.电量约束
public class BatteryNotLowTracker extends BroadcastReceiverConstraintTracker<Boolean> {

    private static final String TAG = Logger.tagWithPrefix("BatteryNotLowTracker");
    //电量低的阈值 <=15%
    static final float BATTERY_LOW_THRESHOLD = 0.15f;

    public BatteryNotLowTracker(@NonNull Context context, @NonNull TaskExecutor taskExecutor) {
        super(context, taskExecutor);
    }
    //获取初始状态
    @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);
    }

    @Override
    public IntentFilter getIntentFilter() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_OKAY);
        intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
        return intentFilter;
    }
    //监听电量变化
    @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;
        }
    }
}
复制代码
代码也相对简单,电量是否低的阈值的 15%,通过监听广播 ACTION_BATTERY_OKAY 和 ACTION_BATTERY_LOW 来决定该约束条件是否满足,这里有个问题 是 阈值是定义的15%,如果各厂商定义了发送广播的阈值,这里会导致不一致,也就是触发条件可能会不一致。

三、任务信息

public final class WorkInfo {
    //任务的ID
    private @NonNull UUID mId;
    //任务状态
    private @NonNull State mState
    //任务输出数据
    private @NonNull Data mOutputData;
    //任务标识 tag
    private @NonNull Set<String> mTags;
   //任务进度
    private @NonNull Data mProgress;
    //任务尝试次数
    private int mRunAttemptCount;

    //任务状态
    public enum State {

        //入队
        ENQUEUED,

        //执行中
        RUNNING,

        //执行成功
        SUCCEEDED,

        //执行失败
        FAILED,

        //任务阻塞
        BLOCKED,

        //任务取消
        CANCELLED;
        //任务是否处于完成状态 (成功、失败、取消)
        public boolean isFinished() {
            return (this == SUCCEEDED || this == FAILED || this == CANCELLED);
        }
    }
}
复制代码

任务的信息包含了一系列状态,及任务执行过程中的一些数据,如进度、状态等,WorkSpec主要是写入数据库相关的任务信息的数据

四、任务执行

有了任务创建、任务约束、任务约束,我们来看下任务是怎么执行的。

单次任务:

//上层调用 调用了enqueue
WorkManager.getInstance(this).enqueue(workRequest)
  
//getInstance  返回了 实现类 WorkManagerImpl
public static @NonNull WorkManager getInstance(@NonNull Context context) {
    return WorkManagerImpl.getInstance(context);
}

//WorkManager.java  将workRequest 转换成列表形式然后再次调用enqueue
@NonNull
public final Operation enqueue(@NonNull WorkRequest workRequest) {
    return enqueue(Collections.singletonList(workRequest));
}

//WorkManagerImpl.java
//enqueue 是接口方法 而WorkManagerImpl 是 WorkManager 的实现,我们来看下而WorkManagerImpl的实现
 @Override
 @NonNull
 public Operation enqueue(@NonNull List<? extends WorkRequest> workRequests) {
    //检查入参是否为空
    if (workRequests.isEmpty()) {
        throw new IllegalArgumentException(
                "enqueue needs at least one WorkRequest.");
    }
    //new WorkContinuationImpl,然后调用WorkContinuationImpl的 enqueue
    return new WorkContinuationImpl(this, workRequests).enqueue();
}

//WorkContinuationImpl.java 
WorkContinuationImpl(
            @NonNull WorkManagerImpl workManagerImpl,
            @NonNull List<? extends WorkRequest> work) {
        this(
                workManagerImpl,
                null,
                ExistingWorkPolicy.KEEP,
                work,
                null);
    }
//equeue 方法
  @Override
    public @NonNull Operation enqueue() {
        //校验是否在队列里
        if (!mEnqueued) {
            //包装成runable 然后再线程池执行该runabl人,runable 持有 WorkContinuationImpl
            EnqueueRunnable runnable = new EnqueueRunnable(this);
            mWorkManagerImpl.getWorkTaskExecutor().executeOnBackgroundThread(runnable);
            mOperation = runnable.getOperation();
        } else {
            Logger.get().warning(TAG,
                    String.format("Already enqueued work ids (%s)", TextUtils.join(", ", mIds)));
        }
        return mOperation;
    }

//上述方法调用线程池执行runable,那么我们看下 runable 的run方法
 @Override
    public void run() {
        try {
            //检查是否有循环
            if (mWorkContinuation.hasCycles()) {
                throw new IllegalStateException(
                        String.format("WorkContinuation has cycles (%s)", mWorkContinuation));
            }
            //添加到数据库
            boolean needsScheduling = addToDatabase();
            //如果返回为真 则 启动RescheduleReceiver  然后调用scheduleWorkInBackground()
            if (needsScheduling) {
                // Enable RescheduleReceiver, only when there are Worker's that need scheduling.
                final Context context =
                        mWorkContinuation.getWorkManagerImpl().getApplicationContext();
                PackageManagerHelper.setComponentEnabled(context, RescheduleReceiver.class, true);          //后台执行
                scheduleWorkInBackground();
            }
            mOperation.setState(Operation.SUCCESS);
        } catch (Throwable exception) {
            mOperation.setState(new Operation.State.FAILURE(exception));
        }
    }

//我们先看下addToDatabase
//获取数据库 然后调用了 processContinuation
    @VisibleForTesting
    public boolean addToDatabase() {
        WorkManagerImpl workManagerImpl = mWorkContinuation.getWorkManagerImpl();
        WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();
        workDatabase.beginTransaction();
        try {
            boolean needsScheduling = processContinuation(mWorkContinuation);
            workDatabase.setTransactionSuccessful();
            return needsScheduling;
        } finally {
            workDatabase.endTransaction();
        }
    }

 private static boolean processContinuation(@NonNull WorkContinuationImpl workContinuation) {
        boolean needsScheduling = false;
        List<WorkContinuationImpl> parents = workContinuation.getParents();
        if (parents != null) {
            for (WorkContinuationImpl parent : parents) {
                if (!parent.isEnqueued()) {
                    needsScheduling |= processContinuation(parent);
                } else {
                    Logger.get().warning(TAG, String.format("Already enqueued work ids (%s).",
                            TextUtils.join(", ", parent.getIds())));
                }
            }
        }
        //加入 parents 为空,会调用enqueueContinuation
        needsScheduling |= enqueueContinuation(workContinuation);
        return needsScheduling;
    }

//
 private static boolean enqueueContinuation(@NonNull WorkContinuationImpl workContinuation) {
        Set<String> prerequisiteIds = WorkContinuationImpl.prerequisitesFor(workContinuation);

        boolean needsScheduling = enqueueWorkWithPrerequisites(
                workContinuation.getWorkManagerImpl(),
                workContinuation.getWork(),
                prerequisiteIds.toArray(new String[0]),
                workContinuation.getName(),
                workContinuation.getExistingWorkPolicy());

        workContinuation.markEnqueued();
        return needsScheduling;
    }

    private static boolean enqueueWorkWithPrerequisites(
            WorkManagerImpl workManagerImpl,
            @NonNull List<? extends WorkRequest> workList,
            String[] prerequisiteIds,
            String name,
            ExistingWorkPolicy existingWorkPolicy) {

        boolean needsScheduling = false;

        long currentTimeMillis = System.currentTimeMillis();
        WorkDatabase workDatabase = workManagerImpl.getWorkDatabase();

        boolean hasPrerequisite = (prerequisiteIds != null && prerequisiteIds.length > 0);
        boolean hasCompletedAllPrerequisites = true;
        boolean hasFailedPrerequisites = false;
        boolean hasCancelledPrerequisites = false;

        if (hasPrerequisite) {
            for (String id : prerequisiteIds) {
                WorkSpec prerequisiteWorkSpec = workDatabase.workSpecDao().getWorkSpec(id);
                if (prerequisiteWorkSpec == null) {
                    Logger.get().error(TAG,
                            String.format("Prerequisite %s doesn't exist; not enqueuing", id));
                    return false;
                }

                WorkInfo.State prerequisiteState = prerequisiteWorkSpec.state;
                hasCompletedAllPrerequisites &= (prerequisiteState == SUCCEEDED);
                if (prerequisiteState == FAILED) {
                    hasFailedPrerequisites = true;
                } else if (prerequisiteState == CANCELLED) {
                    hasCancelledPrerequisites = true;
                }
            }
        }

        boolean isNamed = !TextUtils.isEmpty(name);
        boolean shouldApplyExistingWorkPolicy = isNamed && !hasPrerequisite;
        if (shouldApplyExistingWorkPolicy) {
            List<WorkSpec.IdAndState> existingWorkSpecIdAndStates =
                    workDatabase.workSpecDao().getWorkSpecIdAndStatesForName(name);

            if (!existingWorkSpecIdAndStates.isEmpty()) {
                // 策略处理
                if (existingWorkPolicy == APPEND || existingWorkPolicy == APPEND_OR_REPLACE) {
                    DependencyDao dependencyDao = workDatabase.dependencyDao();
                    List<String> newPrerequisiteIds = new ArrayList<>();
                    for (WorkSpec.IdAndState idAndState : existingWorkSpecIdAndStates) {
                        if (!dependencyDao.hasDependents(idAndState.id)) {
                            hasCompletedAllPrerequisites &= (idAndState.state == SUCCEEDED);
                            if (idAndState.state == FAILED) {
                                hasFailedPrerequisites = true;
                            } else if (idAndState.state == CANCELLED) {
                                hasCancelledPrerequisites = true;
                            }
                            newPrerequisiteIds.add(idAndState.id);
                        }
                    }
                    if (existingWorkPolicy == APPEND_OR_REPLACE) {
                        if (hasCancelledPrerequisites || hasFailedPrerequisites) {
                            // Delete all WorkSpecs with this name
                            WorkSpecDao workSpecDao = workDatabase.workSpecDao();
                            List<WorkSpec.IdAndState> idAndStates =
                                    workSpecDao.getWorkSpecIdAndStatesForName(name);
                            for (WorkSpec.IdAndState idAndState : idAndStates) {
                                workSpecDao.delete(idAndState.id);
                            }
                            // Treat this as a new chain of work.
                            newPrerequisiteIds = Collections.emptyList();
                            hasCancelledPrerequisites = false;
                            hasFailedPrerequisites = false;
                        }
                    }
                    prerequisiteIds = newPrerequisiteIds.toArray(prerequisiteIds);
                    hasPrerequisite = (prerequisiteIds.length > 0);
                } else {
                    if (existingWorkPolicy == KEEP) {
                        for (WorkSpec.IdAndState idAndState : existingWorkSpecIdAndStates) {
                            if (idAndState.state == ENQUEUED || idAndState.state == RUNNING) {
                                return false;
                            }
                        }
                    }

                    CancelWorkRunnable.forName(name, workManagerImpl, false).run();
                    needsScheduling = true;
                    WorkSpecDao workSpecDao = workDatabase.workSpecDao();
                    for (WorkSpec.IdAndState idAndState : existingWorkSpecIdAndStates) {
                        workSpecDao.delete(idAndState.id);
                    }
                }
            }
        }
        //遍历workRequest
        for (WorkRequest work : workList) {
            //得到work 参数
            WorkSpec workSpec = work.getWorkSpec();

            if (hasPrerequisite && !hasCompletedAllPrerequisites) {
                if (hasFailedPrerequisites) {
                    workSpec.state = FAILED;
                } else if (hasCancelledPrerequisites) {
                    workSpec.state = CANCELLED;
                } else {
                    workSpec.state = BLOCKED;
                }
            } else {
                //如果是周期任务则记录当前的开始时间
                if (!workSpec.isPeriodic()) {
                    workSpec.periodStartTime = currentTimeMillis;
                } else {
                    //否则开始时间记为0
                    workSpec.periodStartTime = 0L;
                }
            }
             //API 23 =< <=25 tryDelegateConstrainedWorkSpec
             //api <=22且usesScheduler 也调用tryDelegateConstrainedWorkSpec
            if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL
                    && Build.VERSION.SDK_INT <= 25) {
                tryDelegateConstrainedWorkSpec(workSpec);
            } else if (Build.VERSION.SDK_INT <= WorkManagerImpl.MAX_PRE_JOB_SCHEDULER_API_LEVEL
                    && usesScheduler(workManagerImpl, Schedulers.GCM_SCHEDULER)) {
                tryDelegateConstrainedWorkSpec(workSpec);
            }

            if (workSpec.state == ENQUEUED) {
                needsScheduling = true;
            }
            //放入数据库
            workDatabase.workSpecDao().insertWorkSpec(workSpec);

            if (hasPrerequisite) {
                for (String prerequisiteId : prerequisiteIds) {
                    Dependency dep = new Dependency(work.getStringId(), prerequisiteId);
                    workDatabase.dependencyDao().insertDependency(dep);
                }
            }
           
            for (String tag : work.getTags()) {
                workDatabase.workTagDao().insert(new WorkTag(tag, work.getStringId()));
            }

            if (isNamed) {
                workDatabase.workNameDao().insert(new WorkName(name, work.getStringId()));
            }
        }
        return needsScheduling;
    }

//电量依赖和 空间依赖 23-25版本ConstraintTrackingWorker 而 26 以上依赖JobScheduler
private static void tryDelegateConstrainedWorkSpec(WorkSpec workSpec) {
        // requiresBatteryNotLow and requiresStorageNotLow require API 26 for JobScheduler.
        // Delegate to ConstraintTrackingWorker between API 23-25.
        Constraints constraints = workSpec.constraints;
        if (constraints.requiresBatteryNotLow() || constraints.requiresStorageNotLow()) {
            String workerClassName = workSpec.workerClassName;
            Data.Builder builder = new Data.Builder();
            // Copy all arguments
            builder.putAll(workSpec.input)
                    .putString(ARGUMENT_CLASS_NAME, workerClassName);
            workSpec.workerClassName = ConstraintTrackingWorker.class.getName();
            workSpec.input = builder.build();
        }
    }


 /**
     * Schedules work on the background scheduler.
     */
    @VisibleForTesting
    public void scheduleWorkInBackground() {
        WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
        Schedulers.schedule(
                workManager.getConfiguration(),
                workManager.getWorkDatabase(),
                workManager.getSchedulers());
    }

复制代码

最后会调到 Schedulers.schedule,将配置、数据库,及scheluer列表传入

我们先看下 schedulers 列表,是workManagerImpl的参数

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public WorkManagerImpl(
        @NonNull Context context,
        @NonNull Configuration configuration,
        @NonNull TaskExecutor workTaskExecutor,
        @NonNull WorkDatabase database) {
    Context applicationContext = context.getApplicationContext();
    Logger.setLogger(new Logger.LogcatLogger(configuration.getMinimumLoggingLevel()));
    //生成schedulers 调用了 createSchedulers
    List<Scheduler> schedulers =
            createSchedulers(applicationContext, configuration, workTaskExecutor);
    Processor processor = new Processor(
            context,
            configuration,
            workTaskExecutor,
            database,
            schedulers);
    internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    public List<Scheduler> createSchedulers(
            @NonNull Context context,
            @NonNull Configuration configuration,
            @NonNull TaskExecutor taskExecutor) {
        //列表项第一个是 createBestAvailableBackgroundScheduler
        //列表项第二个是 GreedyScheduler
        return Arrays.asList(
                Schedulers.createBestAvailableBackgroundScheduler(context, this),
                new GreedyScheduler(context, configuration, taskExecutor, this));
    }

 //Shedulers.java
  @NonNull
    static Scheduler createBestAvailableBackgroundScheduler(
            @NonNull Context context,
            @NonNull WorkManagerImpl workManager) {

        Scheduler scheduler;
        //23及以上 采用SystemJobScheduler,同时依赖SystemJobService
        if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
            scheduler = new SystemJobScheduler(context, workManager);
            setComponentEnabled(context, SystemJobService.class, true);
            Logger.get().debug(TAG, "Created SystemJobScheduler and enabled SystemJobService");
        } else {
            //23以下 采用反射获取GcmScheduler,如果获取不到,采用SystemAlarmScheduler,并用SystemAlarmService
            scheduler = tryCreateGcmBasedScheduler(context);
            if (scheduler == null) {
                scheduler = new SystemAlarmScheduler(context);
                setComponentEnabled(context, SystemAlarmService.class, true);
                Logger.get().debug(TAG, "Created SystemAlarmScheduler");
            }
        }
        return scheduler;
    }

    @Nullable
    private static Scheduler tryCreateGcmBasedScheduler(@NonNull Context context) {
        try {
            Class<?> klass = Class.forName(GCM_SCHEDULER);
            Scheduler scheduler =
                    (Scheduler) klass.getConstructor(Context.class).newInstance(context);
            Logger.get().debug(TAG, String.format("Created %s", GCM_SCHEDULER));
            return scheduler;
        } catch (Throwable throwable) {
            Logger.get().debug(TAG, "Unable to create GCM Scheduler", throwable);
            return null;
        }
    }
复制代码

约束是如何生效的?我们知道最后调用是 Sheduler.shedule,我们看下这个方法:

@Override
public void schedule(@NonNull WorkSpec... workSpecs) {
    if (mIsMainProcess == null) {
        mIsMainProcess = TextUtils.equals(mContext.getPackageName(), getProcessName());
    }

    if (!mIsMainProcess) {
        Logger.get().info(TAG, "Ignoring schedule request in non-main process");
        return;
    }

    registerExecutionListenerIfNeeded();
    //有约束的work参数集合
    Set<WorkSpec> constrainedWorkSpecs = new HashSet<>();
    //有约束的workId集合
    Set<String> constrainedWorkSpecIds = new HashSet<>();

    for (WorkSpec workSpec : workSpecs) {
        long nextRunTime = workSpec.calculateNextRunTime();
        long now = System.currentTimeMillis();
        if (workSpec.state == WorkInfo.State.ENQUEUED) {
            if (now < nextRunTime) {
                // Future work
                if (mDelayedWorkTracker != null) {
                    mDelayedWorkTracker.schedule(workSpec);
                }
            } else if (workSpec.hasConstraints()) {
                if (SDK_INT >= 23 && workSpec.constraints.requiresDeviceIdle()) {
                    //23以上忽略设备空闲的约束
                    Logger.get().debug(TAG,
                            String.format("Ignoring WorkSpec %s, Requires device idle.",
                                    workSpec));
                } else if (SDK_INT >= 24 && workSpec.constraints.hasContentUriTriggers()) {
                    //24以上忽略contentUri 约束
                    Logger.get().debug(TAG,
                            String.format("Ignoring WorkSpec %s, Requires ContentUri triggers.",
                                    workSpec));
                } else {
                    //将约束添加到集合
                    constrainedWorkSpecs.add(workSpec);
                    //将任务id 添加到集合
                    constrainedWorkSpecIds.add(workSpec.id);
                }
            } else {
                //没有约束 直接调用startWork
                Logger.get().debug(TAG, String.format("Starting work for %s", workSpec.id));
                mWorkManagerImpl.startWork(workSpec.id);
            }
        }
    }

    // onExecuted() which is called on the main thread also modifies the list of mConstrained
    // WorkSpecs. Therefore we need to lock here.
    synchronized (mLock) {
        if (!constrainedWorkSpecs.isEmpty()) {
            Logger.get().debug(TAG, String.format("Starting tracking for [%s]",
                    TextUtils.join(",", constrainedWorkSpecIds)));
            mConstrainedWorkSpecs.addAll(constrainedWorkSpecs);
            mWorkConstraintsTracker.replace(mConstrainedWorkSpecs);
        }
    }
}
复制代码

有约束的情况下并没有执行startwork,我们先假设没有约束,看下startwork

/**
 * @param workSpecId The {@link WorkSpec} id to start
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(@NonNull String workSpecId) {
    startWork(workSpecId, null);
}

/**
 * @param workSpecId The {@link WorkSpec} id to start
 * @param runtimeExtras The {@link WorkerParameters.RuntimeExtras} associated with this work
 * @hide
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public void startWork(
        @NonNull String workSpecId,
        @Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
    //调用后台线程 执行封装成的runable
    mWorkTaskExecutor
            .executeOnBackgroundThread(
                    new StartWorkRunnable(this, workSpecId, runtimeExtras));
}

//StartWorkRunnable.java 调用了 getProcessor.startWork
 @Override
    public void run() {
        mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
    }

//Processor.java 包装成workWrapper 然后调用线程池执行
    public boolean startWork(
            @NonNull String id,
            @Nullable WorkerParameters.RuntimeExtras runtimeExtras) {

        WorkerWrapper workWrapper;
        synchronized (mLock) {
            // Work may get triggered multiple times if they have passing constraints
            // and new work with those constraints are added.
            if (isEnqueued(id)) {
                Logger.get().debug(
                        TAG,
                        String.format("Work %s is already enqueued for processing", id));
                return false;
            }

            workWrapper =
                    new WorkerWrapper.Builder(
                            mAppContext,
                            mConfiguration,
                            mWorkTaskExecutor,
                            this,
                            mWorkDatabase,
                            id)
                            .withSchedulers(mSchedulers)
                            .withRuntimeExtras(runtimeExtras)
                            .build();
            ListenableFuture<Boolean> future = workWrapper.getFuture();
            future.addListener(
                    new FutureListener(this, id, future),
                    mWorkTaskExecutor.getMainThreadExecutor());
            mEnqueuedWorkMap.put(id, workWrapper);
        }
        mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
        Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
        return true;
    }

//WorkRapper.java  run 方法
  @WorkerThread
    @Override
    public void run() {
        mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
        mWorkDescription = createWorkDescription(mTags);
        //调用runworker
        runWorker();
    }

    private void runWorker() {
        if (tryCheckForInterruptionAndResolve()) {
            return;
        }

        mWorkDatabase.beginTransaction();
        try {
            //获取任务参数
            mWorkSpec = mWorkSpecDao.getWorkSpec(mWorkSpecId);
            if (mWorkSpec == null) {
                Logger.get().error(
                        TAG,
                        String.format("Didn't find WorkSpec for id %s", mWorkSpecId));
                resolve(false);
                return;
            }
            if (mWorkSpec.state != ENQUEUED) {
                resolveIncorrectStatus();
                mWorkDatabase.setTransactionSuccessful();
                Logger.get().debug(TAG,
                        String.format("%s is not in ENQUEUED state. Nothing more to do.",
                                mWorkSpec.workerClassName));
                return;
            }

            //周期性任务 和 延时任务处理
            if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
                long now = System.currentTimeMillis();
                //是不是第一次执行 并计算下次要执行任务的时间
                boolean isFirstRun = mWorkSpec.periodStartTime == 0;
                if (!isFirstRun && now < mWorkSpec.calculateNextRunTime()) {
                    Logger.get().debug(TAG,
                            String.format(
                                    "Delaying execution for %s because it is being executed "
                                            + "before schedule.",
                                    mWorkSpec.workerClassName));
                    resolve(true);
                    return;
                }
            }
            mWorkDatabase.setTransactionSuccessful();
        } finally {
            mWorkDatabase.endTransaction();
        }
        //携带的参数处理
        Data input;
        if (mWorkSpec.isPeriodic()) {
            input = mWorkSpec.input;
        } else {
            InputMergerFactory inputMergerFactory = mConfiguration.getInputMergerFactory();
            String inputMergerClassName = mWorkSpec.inputMergerClassName;
            InputMerger inputMerger =
                    inputMergerFactory.createInputMergerWithDefaultFallback(inputMergerClassName);
            if (inputMerger == null) {
                Logger.get().error(TAG, String.format("Could not create Input Merger %s",
                        mWorkSpec.inputMergerClassName));
                setFailedAndResolve();
                return;
            }
            List<Data> inputs = new ArrayList<>();
            inputs.add(mWorkSpec.input);
            inputs.addAll(mWorkSpecDao.getInputsFromPrerequisites(mWorkSpecId));
            input = inputMerger.merge(inputs);
        }

        WorkerParameters params = new WorkerParameters(
                UUID.fromString(mWorkSpecId),
                input,
                mTags,
                mRuntimeExtras,
                mWorkSpec.runAttemptCount,
                mConfiguration.getExecutor(),
                mWorkTaskExecutor,
                mConfiguration.getWorkerFactory(),
                new WorkProgressUpdater(mWorkDatabase, mWorkTaskExecutor),
                new WorkForegroundUpdater(mWorkDatabase, mForegroundProcessor, mWorkTaskExecutor));
        //执行任务前的判断 是否为空 是否正在使用
        if (mWorker == null) {
            mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback(
                    mAppContext,
                    mWorkSpec.workerClassName,
                    params);
        }

        if (mWorker == null) {
            Logger.get().error(TAG,
                    String.format("Could not create Worker %s", mWorkSpec.workerClassName));
            setFailedAndResolve();
            return;
        }

        if (mWorker.isUsed()) {
            Logger.get().error(TAG,
                    String.format("Received an already-used Worker %s; WorkerFactory should return "
                            + "new instances",
                            mWorkSpec.workerClassName));
            setFailedAndResolve();
            return;
        }
        mWorker.setUsed();
        //尝试运行任务
        if (trySetRunning()) {
            if (tryCheckForInterruptionAndResolve()) {
                return;
            }

            final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
            //调用startwork 方法 运行在主线程
            mWorkTaskExecutor.getMainThreadExecutor()
                    .execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Logger.get().debug(TAG, String.format("Starting work for %s",
                                        mWorkSpec.workerClassName));
                                mInnerFuture = mWorker.startWork();
                                future.setFuture(mInnerFuture);
                            } catch (Throwable e) {
                                future.setException(e);
                            }

                        }
                    });

            //运行结果监听
            final String workDescription = mWorkDescription;
            future.addListener(new Runnable() {
                @Override
                @SuppressLint("SyntheticAccessor")
                public void run() {
                    try {
                        
                        ListenableWorker.Result result = future.get();
                        if (result == null) {
                            Logger.get().error(TAG, String.format(
                                    "%s returned a null result. Treating it as a failure.",
                                    mWorkSpec.workerClassName));
                        } else {
                            Logger.get().debug(TAG, String.format("%s returned a %s result.",
                                    mWorkSpec.workerClassName, result));
                            mResult = result;
                        }
                    } catch (CancellationException exception) {
                        // Cancellations need to be treated with care here because innerFuture
                        // cancellations will bubble up, and we need to gracefully handle that.
                        Logger.get().info(TAG, String.format("%s was cancelled", workDescription),
                                exception);
                    } catch (InterruptedException | ExecutionException exception) {
                        Logger.get().error(TAG,
                                String.format("%s failed because it threw an exception/error",
                                        workDescription), exception);
                    } finally {
                        onWorkFinished();
                    }
                }
            }, mWorkTaskExecutor.getBackgroundExecutor());
        } else {
            resolveIncorrectStatus();
        }
    }
复制代码

任务约束如何生效的?

上文我们看到GreedyScheduler 在有约束的情况下并没有调用startwork,那什么时候会调用

//精简过省略部分代码,实现了 WorkConstraintsCallback 接口
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class GreedyScheduler implements Scheduler, WorkConstraintsCallback{

    //约束的总处理
    private final WorkConstraintsTracker mWorkConstraintsTracker;
    //约束的条件
    private final Set<WorkSpec> mConstrainedWorkSpecs = new HashSet<>();
 

    public GreedyScheduler(
            @NonNull Context context,
            @NonNull Configuration configuration,
            @NonNull TaskExecutor taskExecutor,
            @NonNull WorkManagerImpl workManagerImpl) {
        //构造函数初始初始化约束总处理
        mWorkConstraintsTracker = new WorkConstraintsTracker(context, taskExecutor, this);
       
    }

    
    //实现了接口所有约束都符合的回调 会调用stratwork
    @Override
    public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
        for (String workSpecId : workSpecIds) {
            Logger.get().debug(
                    TAG,
                    String.format("Constraints met: Scheduling work ID %s", workSpecId));
            mWorkManagerImpl.startWork(workSpecId);
        }
    }
    //实现了接口所有约束都不符合的回调 会调用stopwork
    @Override
    public void onAllConstraintsNotMet(@NonNull List<String> workSpecIds) {
        for (String workSpecId : workSpecIds) {
            Logger.get().debug(TAG,
                    String.format("Constraints not met: Cancelling work ID %s", workSpecId));
            mWorkManagerImpl.stopWork(workSpecId);
        }
    }
}
复制代码

GreedyScheduler 实现了 WorkConstraintsCallback 接口,在所有约束满足的时候会回调onAllConstraintsMet,然后调用startwork

五、总结

1.WorkManager 的真正实现是WorkManagerImpl,通过getInstance 获取并未进行初始化,WorkManagerInitializer 继承自contentProvider,在Oncreate 时调用了 initialize 方法完成初始化,同时进行线程池、调度器等的初始化
2.startwork 的调用是在主线程,然后又通过后台线程池执行了 dowork
3.任务在APP杀死的情况下再启动能执行是因为将任务相关信息写进了数据库,app 启动后可以恢复
4. 任务调度器:API >=23 时 会生成 SystemJobScheduler 并配合SystemJobService 来调度任务;api < 23时 23以下 采用反射获取GcmScheduler,如果获取不到,采用SystemAlarmScheduler,并用SystemAlarmService 来调度任务;第二个调度器实现是GreedyScheduler
5.任务约束
(1) 网络约束:API>=24 时采用 NetworkStateCallback 来监听网络连接状态的变更,在api < 24时采用BroadcastReceiver 来监听系统广播CONNECTIVITY_ACTION 来监听网络连接状态的变更
(2) 存储约束:过监听广播ACTION_DEVICE_STORAGE_OK 和 ACTION_DEVICE_STORAGE_LOW 来决定设备存储这个约束条件
(3) 电量约束:电量是否低的阈值是 15%,通过监听广播 ACTION_BATTERY_OKAY 和 ACTION_BATTERY_LOW 来决定该约束条件是否满足
(4)充电约束:23 以下通过监听广播ACTION_POWER_CONNECTED 和 ACTION_POWER_DISCONNECTED 来判断充电和断电,23及以上通过监听 ACTION_CHARGING 和 ACTION_DISCHARGING 来判断充电状态
6. Worker 执行过程(GreedyScheduler):
(1) Worker 包装成WorkRequest,添加约束等条件
(2) 调用WorkManagerImpl 的 enqueue 方法,WorkManagerImpl 将自身和 WorkRequest 封装成WorkContinuationImpl,然后调用WorkContinuationImpl 的enqueue 方法
(3) WorkContinuationImpl enqueue 将自身封装成 EnqueueRunnable,然后调用后台线程池执行 EnqueueRunnable
(4) EnqueueRunnable 的run 方法 会先将自己存入数据库,然后根据是否需要调度,启用后台调度scheduleWorkInBackground
(5) 后台调度及 WorkManager 初始化时的两个调度器Schedulers,然后调用 schedule 方法;
(6) schedule 方法会根据任务是否有约束决定是约束条件满足后开始执行任务还是 立刻执行任务(WorkManagerImpl.startwork)
(7) WorkManagerImpl.startwork 将workSpecId 和 WorkManagerImpl 封装成StartWorkRunnable,然后通过任务执行器 后台执行任务
(8) StartWorkRunnable 的run 方法会执行Processor.startwork 方法
(9)Processor.startwork 会根据 workId 包装成 WorkerWrapper,然后通过人去执行器 执行WorkerWrapper
(10)WorkerWrapper 的run 方法会执行 runworker,然后根据任务的一系列状态判断,最后会在主线程执行 Worker.startWorker,而startWorker 内部又在子线程执行了 dowork方法
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享