美文网首页
WorkMananger

WorkMananger

作者: 剑心_路喜 | 来源:发表于2023-02-05 17:07 被阅读0次

    引用

    implementation "androidx.work:work-runtime:2.7.1"
    

    WorkManager 引用后,直接buildbebug包,看到在 AndroidManifest.xml文件中添加了很多的 providerservicereceiver 便签。这是为什么呢?

    那我们只是多引入一个Work的引用,只能在Work中查找了。

    <?xml version="1.0" encoding="utf-8"?>
    <!--
      ~ Copyright (C) 2016 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.
    -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="androidx.work" >
    
        <uses-sdk
            android:minSdkVersion="14"
            android:targetSdkVersion="31" />
    
        <uses-permission android:name="android.permission.WAKE_LOCK" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
        <application>
            <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" />
            </provider>
    
            <service
                android:name="androidx.work.impl.background.systemalarm.SystemAlarmService"
                android:directBootAware="false"
                android:enabled="@bool/enable_system_alarm_service_default"
                android:exported="false"
                tools:targetApi="n" />
            <service
                android:name="androidx.work.impl.background.systemjob.SystemJobService"
                android:directBootAware="false"
                android:enabled="@bool/enable_system_job_service_default"
                android:exported="true"
                android:permission="android.permission.BIND_JOB_SERVICE"
                tools:targetApi="n" />
            <service
                android:name="androidx.work.impl.foreground.SystemForegroundService"
                android:directBootAware="false"
                android:enabled="@bool/enable_system_foreground_service_default"
                android:exported="false"
                tools:targetApi="n" />
    
            <receiver
                android:name="androidx.work.impl.utils.ForceStopRunnable$BroadcastReceiver"
                android:directBootAware="false"
                android:enabled="true"
                android:exported="false"
                tools:targetApi="n" />
            <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
                    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.intent.action.BATTERY_OKAY" />
                    <action android:name="android.intent.action.BATTERY_LOW" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$StorageNotLowProxy"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
                    <action android:name="android.intent.action.DEVICE_STORAGE_OK" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.background.systemalarm.RescheduleReceiver"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.TIME_SET" />
                    <action android:name="android.intent.action.TIMEZONE_CHANGED" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxyUpdateReceiver"
                android:directBootAware="false"
                android:enabled="@bool/enable_system_alarm_service_default"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="androidx.work.impl.background.systemalarm.UpdateProxies" />
                </intent-filter>
            </receiver>
            <receiver
                android:name="androidx.work.impl.diagnostics.DiagnosticsReceiver"
                android:directBootAware="false"
                android:enabled="true"
                android:exported="true"
                android:permission="android.permission.DUMP"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="androidx.work.diagnostics.REQUEST_DIAGNOSTICS" />
                </intent-filter>
            </receiver>
        </application>
    
    </manifest>
    

    可以看到 workAndroidManifest.xml 文件中引用。这个不是今天的重点。 今天分析WorkManager是如何工作的

    分析

    WorkManager初始化

     <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" />
            </provider>
    
    public final class InitializationProvider extends ContentProvider {
        @Override
        public boolean onCreate() {
            Context context = getContext();
            if (context != null) {
                AppInitializer.getInstance(context).discoverAndInitialize();
            } else {
                throw new StartupException("Context cannot be null");
            }
            return true;
        }
    }
    
    public final class AppInitializer {
            void discoverAndInitialize() {
            try {
                Trace.beginSection(SECTION_NAME);
                ComponentName provider = new ComponentName(mContext.getPackageName(),
                        InitializationProvider.class.getName());
                ProviderInfo providerInfo = mContext.getPackageManager()
                        .getProviderInfo(provider, GET_META_DATA);
                //拿到meta-data 标签
                Bundle metadata = providerInfo.metaData;
                //androidx.startup
                String startup = mContext.getString(R.string.androidx_startup);
                if (metadata != null) {
                    Set<Class<?>> initializing = new HashSet<>();
                    Set<String> keys = metadata.keySet();
                    for (String key : keys) {
                        String value = metadata.getString(key, null);
                        if (startup.equals(value)) {
                            Class<?> clazz = Class.forName(key);
                            //clazz 是 Initializer的子类才执行 if
                            if (Initializer.class.isAssignableFrom(clazz)) {
                                Class<? extends Initializer<?>> component =
                                        (Class<? extends Initializer<?>>) clazz;
                                mDiscovered.add(component);
                                if (StartupLogger.DEBUG) {
                                    StartupLogger.i(String.format("Discovered %s", key));
                                }
                                //初始化
                                doInitialize(component, initializing);
                            }
                        }
                    }
                }
            } catch (PackageManager.NameNotFoundException | ClassNotFoundException exception) {
                throw new StartupException(exception);
            } finally {
                Trace.endSection();
            }
        }
    }    
    
    public interface Initializer<T> {
    
        /**
         * Initializes and a component given the application {@link Context}
         *
         * @param context The application context.
         */
        @NonNull
        T create(@NonNull Context context);
    
        /**
         * @return A list of dependencies that this {@link Initializer} depends on. This is
         * used to determine initialization order of {@link Initializer}s.
         * <br/>
         * For e.g. if a {@link Initializer} `B` defines another
         * {@link Initializer} `A` as its dependency, then `A` gets initialized before `B`.
         */
        @NonNull
        List<Class<? extends Initializer<?>>> dependencies();
    }
    
    

    Initializer 是一个接口,看到里面有两个方法 createdependencies

    doInitialize(component, initializing);方法里是真正的初始化,我们看看里面写的啥

        <T> T doInitialize(
                @NonNull Class<? extends Initializer<?>> component,
                @NonNull Set<Class<?>> initializing) {
            synchronized (sLock) {
                boolean isTracingEnabled = Trace.isEnabled();
                try {
                    if (isTracingEnabled) {
                        // Use the simpleName here because section names would get too big otherwise.
                        Trace.beginSection(component.getSimpleName());
                    }
                    if (initializing.contains(component)) {
                        String message = String.format(
                                "Cannot initialize %s. Cycle detected.", component.getName()
                        );
                        throw new IllegalStateException(message);
                    }
                    Object result;
                    if (!mInitialized.containsKey(component)) {
                        initializing.add(component);
                        try {
                            //反射 new出对象
                            Object instance = component.getDeclaredConstructor().newInstance();
                            Initializer<?> initializer = (Initializer<?>) instance;
                            List<Class<? extends Initializer<?>>> dependencies =
                                    initializer.dependencies();
    
                            if (!dependencies.isEmpty()) {
                                for (Class<? extends Initializer<?>> clazz : dependencies) {
                                    if (!mInitialized.containsKey(clazz)) {
                                        doInitialize(clazz, initializing);
                                    }
                                }
                            }
                            if (StartupLogger.DEBUG) {
                                StartupLogger.i(String.format("Initializing %s", component.getName()));
                            }
                            //调用 create方法
                            result = initializer.create(mContext);
                            if (StartupLogger.DEBUG) {
                                StartupLogger.i(String.format("Initialized %s", component.getName()));
                            }
                            initializing.remove(component);
                            mInitialized.put(component, result);
                        } catch (Throwable throwable) {
                            throw new StartupException(throwable);
                        }
                    } else {
                        result = mInitialized.get(component);
                    }
                    return (T) result;
                } finally {
                    Trace.endSection();
                }
            }
        }
    
    public final class WorkManagerInitializer implements Initializer<WorkManager> {
    
        private static final String TAG = Logger.tagWithPrefix("WrkMgrInitializer");
    
        @NonNull
        @Override
        public WorkManager create(@NonNull Context context) {
            // Initialize WorkManager with the default configuration.
            Logger.get().debug(TAG, "Initializing WorkManager with default configuration.");
            WorkManager.initialize(context, new Configuration.Builder().build());
            return WorkManager.getInstance(context);
        }
    
        @NonNull
        @Override
        public List<Class<? extends androidx.startup.Initializer<?>>> dependencies() {
            return Collections.emptyList();
        }
    }
    

    就是调用 WorkManagerInitializercreate, WorkManager.initialize 初始化完成。

        public abstract class WorkManager {
            public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
                WorkManagerImpl.initialize(context, configuration);
            }
      }  
      
     public class WorkManagerImpl extends WorkManager {     
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
            synchronized (sLock) {
                if (sDelegatedInstance != null && sDefaultInstance != null) {
                    throw new IllegalStateException("WorkManager is already initialized.  Did you "
                            + "try to initialize it manually without disabling "
                            + "WorkManagerInitializer? See "
                            + "WorkManager#initialize(Context, Configuration) or the class level "
                            + "Javadoc for more information.");
                }
    
                if (sDelegatedInstance == null) {
                    context = context.getApplicationContext();
                    if (sDefaultInstance == null) {
                        sDefaultInstance = new WorkManagerImpl(
                                context,
                                configuration,
                                new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
                    }
                    sDelegatedInstance = sDefaultInstance;
                }
            }
        }
        }    
    

    new出WorkManagerImpl 对象,传入contextconfigurationWorkManagerTaskExecutor三个参数

       @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public WorkManagerImpl(
                @NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor workTaskExecutor) {
            this(context,
                    configuration,
                    workTaskExecutor,
                    context.getResources().getBoolean(R.bool.workmanager_test_configuration));
        }
          @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public WorkManagerImpl(
                @NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor workTaskExecutor,
                boolean useTestDatabase) {
            //WorkDatabase.create,
            this(context,
                    configuration,
                    workTaskExecutor,
                    WorkDatabase.create(
                            context.getApplicationContext(),
                            workTaskExecutor.getBackgroundExecutor(),
                            useTestDatabase)
            );
        }
    
        @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()));
                    //创建调度器
            List<Scheduler> schedulers =
                    createSchedulers(applicationContext, configuration, workTaskExecutor);
            Processor processor = new Processor(
                    context,
                    configuration,
                    workTaskExecutor,
                    database,
                    schedulers);
            internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
        }
    

    步骤一 createSchedulers

    • GreedyScheduler 埋下伏笔,调度器
        public List<Scheduler> createSchedulers(
                @NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor taskExecutor) {
    
            return Arrays.asList(
                    Schedulers.createBestAvailableBackgroundScheduler(context, this),
                    // Specify the task executor directly here as this happens before internalInit.
                    // GreedyScheduler creates ConstraintTrackers and controllers eagerly.
                    new GreedyScheduler(context, configuration, taskExecutor, this));
        }
    
    

    步骤二:Processor()用来管理Schedulers的执行

    public WorkManagerImpl(...) {
          ...
            List<Scheduler> schedulers = createSchedulers(applicationContext, workTaskExecutor);
            Processor processor = new Processor(
                    context,
                    configuration,
                    workTaskExecutor,
                    database,
                    schedulers);
            ....
        }
    

    步骤三:internalInit()真正的初始化。先看createSchedulers()的实现。

        private void internalInit(@NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor workTaskExecutor,
                @NonNull WorkDatabase workDatabase,
                @NonNull List<Scheduler> schedulers,
                @NonNull Processor processor) {
    
            context = context.getApplicationContext();
            mContext = context;
            mConfiguration = configuration;
            mWorkTaskExecutor = workTaskExecutor;
            mWorkDatabase = workDatabase;
            mSchedulers = schedulers;
            mProcessor = processor;
            mPreferenceUtils = new PreferenceUtils(workDatabase);
            mForceStopRunnableCompleted = false;
    
            // Check for direct boot mode
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.isDeviceProtectedStorage()) {
                throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");
            }
    
            // Checks for app force stops.  检查应用程序强制停止。
            mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
        }
    
    ForceStopRunnable.java类
      
        @Override
        public void run() {
            try {
                if (!multiProcessChecks()) {
                    return;
                }
                while (true) {
                    // Migrate the database to the no-backup directory if necessary.
                    WorkDatabasePathHelper.migrateDatabase(mContext);
                    // Clean invalid jobs attributed to WorkManager, and Workers that might have been
                    // interrupted because the application crashed (RUNNING state).
                    Logger.get().debug(TAG, "Performing cleanup operations.");
                    try {
                        forceStopRunnable();
                        break;
                    } catch (SQLiteCantOpenDatabaseException
                            | SQLiteDatabaseCorruptException
                            | SQLiteDatabaseLockedException
                            | SQLiteTableLockedException
                            | SQLiteConstraintException
                            | SQLiteAccessPermException exception) {
                        mRetryCount++;
                        if (mRetryCount >= MAX_ATTEMPTS) {
                            // ForceStopRunnable is usually the first thing that accesses a database
                            // (or an app's internal data directory). This means that weird
                            // PackageManager bugs are attributed to ForceStopRunnable, which is
                            // unfortunate. This gives the developer a better error
                            // message.
                            String message = "The file system on the device is in a bad state. "
                                    + "WorkManager cannot access the app's internal data store.";
                            Logger.get().error(TAG, message, exception);
                            IllegalStateException throwable = new IllegalStateException(message,
                                    exception);
                            InitializationExceptionHandler exceptionHandler =
                                    mWorkManager.getConfiguration().getExceptionHandler();
                            if (exceptionHandler != null) {
                                Logger.get().debug(TAG,
                                        "Routing exception to the specified exception handler",
                                        throwable);
                                exceptionHandler.handleException(throwable);
                                break;
                            } else {
                                throw throwable;
                            }
                        } else {
                            long duration = mRetryCount * BACKOFF_DURATION_MS;
                            Logger.get()
                                    .debug(TAG, String.format("Retrying after %s", duration),
                                            exception);
                            sleep(mRetryCount * BACKOFF_DURATION_MS);
                        }
                    }
                }
            } finally {
                mWorkManager.onForceStopRunnableCompleted();
            }
        }
    

    WorkManager初始化总结

    1.WorkManager初始化是由startup中InitializationProvider这个ContentProvider,通过反射,执行WorkManagerInitializer.create()方法执行的。
    2.会初始化 Configuration,WorkManagerTaskExecutor,WorkDatabase,Schedulers,Processor
    3.GreedyScheduler 埋下伏笔
    4.发现了未完成的,需要重新执行的任务(之前 意外 中断 的继续执行)

    WorkManager执行任务

    无约束执行

    这就是我们自己写的,自定义任务:

    class UploadWorker(context: Context, workerParams: WorkerParameters) :
        Worker(context, workerParams) {
          
        private val TAG = UploadWorker::class.java.simpleName
        
        override fun doWork(): Result {
            Log.d(TAG, "doWork: run ... "); // 就答应了,我们自己写的任务的信息...
            return Result.success();
        }
    }
    
     val oneTimeWorkRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
            .build()
    WorkManager.getInstance(this).enqueue(request)
    

    进入 enqueue 源码中

        // WorkManager.java 类
            @NonNull
        public final Operation enqueue(@NonNull WorkRequest workRequest) {
            return enqueue(Collections.singletonList(workRequest));
        }
    
            @NonNull
        public abstract Operation enqueue(@NonNull List<? extends WorkRequest> requests);
    

    查看enqueue方法的唯一实现:

        //WorkManagerImpl.java 类
        @Override
        @NonNull
        public Operation enqueue(
                @NonNull List<? extends WorkRequest> requests) {
    
            // This error is not being propagated as part of the Operation, as we want the
            // app to crash during development. Having no workRequests is always a developer error.
            if (requests.isEmpty()) {
                throw new IllegalArgumentException(
                        "enqueue needs at least one WorkRequest.");
            }
            return new WorkContinuationImpl(this, requests).enqueue();
        }
    

    创建WorkContinuationImpl对象,再执行enqueue方法。WorkContinuationImplWorkContinuation的子类。

    public class WorkContinuationImpl extends WorkContinuation {
        
      private final WorkManagerImpl mWorkManagerImpl;
        private final String mName;
        private final ExistingWorkPolicy mExistingWorkPolicy;
        private final List<? extends WorkRequest> mWork;
        private final List<String> mIds;
        private final List<String> mAllIds;
        private final List<WorkContinuationImpl> mParents;
    
        private boolean mEnqueued;
        private Operation mOperation;
        //....
        public WorkContinuationImpl(
                @NonNull WorkManagerImpl workManagerImpl,
                @NonNull List<? extends WorkRequest> work) {
            this(
                    workManagerImpl,
                    null,
                    ExistingWorkPolicy.KEEP,
                    work,
                    null);
        } 
        //....
    }  
    

    我们再接着继续看WorkContinuationImplenqueue方法的实现:

        @Override
        public @NonNull Operation enqueue() {
            // Only enqueue if not already enqueued.
            if (!mEnqueued) {
                // The runnable walks the hierarchy of the continuations
                // and marks them enqueued using the markEnqueued() method, parent first.
                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;
        }
    

    我们看到mWorkManagerImpl.getWorkTaskExecutor()后执行了 EnqueueRunnable,那么需要看 EnqueueRunnable 的run函数:

    • mWorkManagerImpl.getWorkTaskExecutor()是前面初始化的时候 new WorkManagerTaskExecutor
        //EnqueueRunnable.java 类
            @Override
        public void run() {
            try {
                if (mWorkContinuation.hasCycles()) {
                    throw new IllegalStateException(
                            String.format("WorkContinuation has cycles (%s)", mWorkContinuation));
                }
                //addToDatabase()的作用是把WorkSpec存入到数据库,并对任务的状态进行校验
                boolean needsScheduling = addToDatabase();
                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));
            }
        }
    

    scheduleWorkInBackground函数

        //EnqueueRunnable.java 
        public void scheduleWorkInBackground() {
            WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
                    //
            Schedulers.schedule(
                    workManager.getConfiguration(),
                    workManager.getWorkDatabase(),
                    workManager.getSchedulers());
        }
    

    调用了Schedulers.schedule()方法,传入了Configuration, WorkDatabase, Scheduler这三个对象。执行schedule()函数:

    //Schedulers.java 类
    public static void schedule(
                @NonNull Configuration configuration,
                @NonNull 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 {
                // Enqueued workSpecs when scheduling limits are applicable.
                eligibleWorkSpecsForLimitedSlots = workSpecDao.getEligibleWorkForScheduling(
                        configuration.getMaxSchedulerLimit());
    
                // Enqueued workSpecs when scheduling limits are NOT applicable.
                allEligibleWorkSpecs = workSpecDao.getAllEligibleWorkSpecsForScheduling(
                        MAX_GREEDY_SCHEDULER_LIMIT);
    
                if (eligibleWorkSpecsForLimitedSlots != null
                        && eligibleWorkSpecsForLimitedSlots.size() > 0) {
                    long now = System.currentTimeMillis();
    
                    // Mark all the WorkSpecs as scheduled.
                    // Calls to Scheduler#schedule() could potentially result in more schedules
                    // on a separate thread. Therefore, this needs to be done first.
                    for (WorkSpec workSpec : eligibleWorkSpecsForLimitedSlots) {
                        //先进行了一系列的数据库操作,然后开始根据条件每个任务进行调度,更新保存数据库等操作
                        workSpecDao.markWorkSpecScheduled(workSpec.id, now);
                    }
                }
                workDatabase.setTransactionSuccessful();
            } finally {
                workDatabase.endTransaction();
            }
    
            if (eligibleWorkSpecsForLimitedSlots != null
                    && eligibleWorkSpecsForLimitedSlots.size() > 0) {
    
                WorkSpec[] eligibleWorkSpecsArray =
                        new WorkSpec[eligibleWorkSpecsForLimitedSlots.size()];
                eligibleWorkSpecsArray =
                        eligibleWorkSpecsForLimitedSlots.toArray(eligibleWorkSpecsArray);
    
                // Delegate to the underlying schedulers.
                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);
                // Delegate to the underlying schedulers.
                for (Scheduler scheduler : schedulers) {
                    if (!scheduler.hasLimitedSchedulingSlots()) {
                        //scheduler.schedule()对每个任务进行调度处理,我们是没有约束的一次性任务,所以看一下GreedyScheduler对于schedule()方法的实现
                        scheduler.schedule(enqueuedWorkSpecsArray);
                    }
                }
            }
        }
    
    // GreedyScheduler.java 类  贪婪调度程序执行 schedule
    public void schedule(@NonNull WorkSpec... workSpecs) {
            if (mInDefaultProcess == null) {
                checkDefaultProcess();
            }
    
            if (!mInDefaultProcess) {
                Logger.get().info(TAG, "Ignoring schedule request in a secondary process");
                return;
            }
    
            registerExecutionListenerIfNeeded();
    
            // Keep track of the list of new WorkSpecs whose constraints need to be tracked.
            // Add them to the known list of constrained WorkSpecs and call replace() on
            // WorkConstraintsTracker. That way we only need to synchronize on the part where we
            // are updating mConstrainedWorkSpecs.
            Set<WorkSpec> constrainedWorkSpecs = new HashSet<>();
            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()) {
                            // Ignore requests that have an idle mode constraint.
                            Logger.get().debug(TAG,
                                    String.format("Ignoring WorkSpec %s, Requires device idle.",
                                            workSpec));
                        } else if (SDK_INT >= 24 && workSpec.constraints.hasContentUriTriggers()) {
                            // Ignore requests that have content uri triggers.
                            Logger.get().debug(TAG,
                                    String.format("Ignoring WorkSpec %s, Requires ContentUri triggers.",
                                            workSpec));
                        } else {
                            constrainedWorkSpecs.add(workSpec);
                            constrainedWorkSpecIds.add(workSpec.id);
                        }
                    } else {
                        Logger.get().debug(TAG, String.format("Starting work for %s", workSpec.id));
                        //由于无约束条件,所以进入此else阶段 的startWork这个函数
                        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);
                }
            }
        }
    

    mWorkManagerImpl.startWork(workSpec.id);

            //WorkManagerImpl类 
       @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public void startWork(@NonNull String workSpecId) {
            startWork(workSpecId, null);
        }
    
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public void startWork(
                @NonNull String workSpecId,
                @Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
            //WorkTaskExecutor对任务进行了调度,下面进入StartWorkRunnable的run()的实现
            mWorkTaskExecutor
                    .executeOnBackgroundThread(
                            new StartWorkRunnable(this, workSpecId, runtimeExtras));
        }
    
    //StartWorkRunnable.java 类
    public class StartWorkRunnable implements Runnable {
            @Override
        public void run() {
            //将任务的信息交给Processor,由Processor调用startWork()去执行任务,下面进入Processor类:
            mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
        }
    }
    
        //Processor.java 类
            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);
            }
          //创建了一个WorkerWrapper的Runnable对象,交由WorkTaskExecutor调度处理。WorkerWrapper的run()方法的实现,下面就要进入 WorkerWrapper类了
            mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper);
            Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id));
            return true;
        }
    
    
    //WorkerWrapper.java 类
            @WorkerThread
        @Override
        public void run() {
            mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
            mWorkDescription = createWorkDescription(mTags);
            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);
                    mWorkDatabase.setTransactionSuccessful();
                    return;
                }
    
                // Do a quick check to make sure we don't need to bail out in case this work is already
                // running, finished, or is blocked.
                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;
                }
    
                // Case 1:
                // Ensure that Workers that are backed off are only executed when they are supposed to.
                // GreedyScheduler can schedule WorkSpecs that have already been backed off because
                // it is holding on to snapshots of WorkSpecs. So WorkerWrapper needs to determine
                // if the ListenableWorker is actually eligible to execute at this point in time.
    
                // Case 2:
                // On API 23, we double scheduler Workers because JobScheduler prefers batching.
                // So is the Work is periodic, we only need to execute it once per interval.
                // Also potential bugs in the platform may cause a Job to run more than once.
    
                if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
                    long now = System.currentTimeMillis();
                    // Allow first run of a PeriodicWorkRequest
                    // to go through. This is because when periodStartTime=0;
                    // calculateNextRunTime() always > now.
                    // For more information refer to b/124274584
                    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));
                        // For AlarmManager implementation we need to reschedule this kind  of Work.
                        // This is not a problem for JobScheduler because we will only reschedule
                        // work if JobScheduler is unaware of a jobId.
                        resolve(true);
                        mWorkDatabase.setTransactionSuccessful();
                        return;
                    }
                }
    
                // Needed for nested transactions, such as when we're in a dependent work request when
                // using a SynchronousExecutor.
                mWorkDatabase.setTransactionSuccessful();
            } finally {
                mWorkDatabase.endTransaction();
            }
    
            // Merge inputs.  This can be potentially expensive code, so this should not be done inside
            // a database transaction.
            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);
            }
    
            final 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));
    
            // Not always creating a worker here, as the WorkerWrapper.Builder can set a worker override
            // in test mode.
            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();
    
            // Try to set the work to the running state.  Note that this may fail because another thread
            // may have modified the DB since we checked last at the top of this function.
            if (trySetRunning()) {
                if (tryCheckForInterruptionAndResolve()) {
                    return;
                }
    
                final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
                final WorkForegroundRunnable foregroundRunnable =
                        new WorkForegroundRunnable(
                                mAppContext,
                                mWorkSpec,
                                mWorker,
                                params.getForegroundUpdater(),
                                mWorkTaskExecutor
                        );
                mWorkTaskExecutor.getMainThreadExecutor().execute(foregroundRunnable);
    
                final ListenableFuture<Void> runExpedited = foregroundRunnable.getFuture();
                runExpedited.addListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            runExpedited.get();
                            Logger.get().debug(TAG,
                                    String.format("Starting work for %s", mWorkSpec.workerClassName));
                            // Call mWorker.startWork() on the main thread.
                          
                            //我们看到调用了mWorker.startWork()方法
                            mInnerFuture = mWorker.startWork();
                            future.setFuture(mInnerFuture);
                        } catch (Throwable e) {
                            future.setException(e);
                        }
                    }
                }, mWorkTaskExecutor.getMainThreadExecutor());
    
                // Avoid synthetic accessors.
                final String workDescription = mWorkDescription;
                future.addListener(new Runnable() {
                    @Override
                    @SuppressLint("SyntheticAccessor")
                    public void run() {
                        try {
                            // If the ListenableWorker returns a null result treat it as a failure.
                            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();
            }
        }
    

    mInnerFuture = mWorker.startWork();

        // Worker。java类
        @WorkerThread
        public abstract @NonNull Result doWork();
    
       @Override
        public final @NonNull ListenableFuture<Result> startWork() {
            mFuture = SettableFuture.create();
            getBackgroundExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                            //此doWork函数 就是 看到曙光了
                        Result result = doWork();
                        mFuture.set(result);
                    } catch (Throwable throwable) {
                        mFuture.setException(throwable);
                    }
    
                }
            });
            return mFuture;
        }
    

    startWork()中调用Worker类的doWork 抽象方法,这就是我们自己写的,自定义任务:

    class UploadWorker(context: Context, workerParams: WorkerParameters) :
        Worker(context, workerParams) {
          
        private val TAG = UploadWorker::class.java.simpleName
        
        override fun doWork(): Result {
            Log.d(TAG, "doWork: run ... "); // 就答应了,我们自己写的任务的信息...
            return Result.success();
        }
    }
    

    无约束条件执行:
    1.WorkManager执行了enqueue()后,创建WorkContinuationImpl对象执行enqueue()方法。
    2.WorkContinuationImpl持有的EnqueueRunnable对象将任务添加到db,并交给Schedulers去调度。
    3.Schedulers将任务交给每一个Scheduler去处理,GreedyScheduler会先处理这个任务。
    4.GreedyScheduler经过一系列判断后,调用WorkManager的startWork()方法执行这种一次性,非延迟,无约束的任务。
    5.WorkManager持有的StartWorkRunnable对象会将任务交给Processor去处理,执行startWork()方法。
    6.Processor创建一个WorkerWrapper对象,由它去调用Worker的startWork()方法。

    有约束条件执行

            //约束条件
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED) // 约束条件,必须是网络连接
                .build()
            // 构建Request
            val request = OneTimeWorkRequest.Builder(MainWorker7::class.java)
                .setConstraints(constraints)
                .build()
            // 加入队列
            WorkManager.getInstance(this).enqueue(request)
    

    在AndroidManifest里有如下receiver注册,我们这里就随便以低电量约束条件为例

           <receiver
                android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy"
                android:directBootAware="false"
                android:enabled="false"
                android:exported="false"
                tools:targetApi="n" >
                <intent-filter>
                    <action android:name="android.intent.action.BATTERY_OKAY" />
                    <action android:name="android.intent.action.BATTERY_LOW" />
                </intent-filter>
            </receiver>
    

    当在电量变化时,收到BATTERY_LOW的广播,在BatteryNotLowProxyonReceive()进行处理:

    abstract class ConstraintProxy extends BroadcastReceiver {
        private static final String TAG = Logger.tagWithPrefix("ConstraintProxy");
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Logger.get().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 {
        }
        //......   
    }    
    

    上面的createConstraintsChangedIntent()执行如下:

            //CommandHandler类
            static Intent createConstraintsChangedIntent(@NonNull Context context) {
            Intent intent = new Intent(context, SystemAlarmService.class);
            intent.setAction(ACTION_CONSTRAINTS_CHANGED);
            return intent;
        }
    

    返回Intent 对象,然后startService启动服务。

    //SystemAlarmService.java  服务类
        public int onStartCommand(Intent intent, int flags, int startId) {
            super.onStartCommand(intent, flags, startId);
            if (mIsShutdown) {
                Logger.get().info(TAG,
                        "Re-initializing SystemAlarmDispatcher after a request to shut-down.");
    
                // Destroy the old dispatcher to complete it's lifecycle.
                mDispatcher.onDestroy();
                // Create a new dispatcher to setup a new lifecycle.
                initializeDispatcher();
                // Set mIsShutdown to false, to correctly accept new commands.
                mIsShutdown = false;
            }
    
            if (intent != null) {
                //调用了SystemAlarmDispatcher.add()方法
                mDispatcher.add(intent, startId);
            }
    
            // If the service were to crash, we want all unacknowledged Intents to get redelivered.
            return Service.START_REDELIVER_INTENT;
        }
    
            //SystemAlarmDispatcher.java 
    
            @MainThread
        public boolean add(@NonNull final Intent intent, final int startId) {
            Logger.get().debug(TAG, String.format("Adding command %s (%s)", intent, startId));
            assertMainThread();
            String action = intent.getAction();
            if (TextUtils.isEmpty(action)) {
                Logger.get().warning(TAG, "Unknown command. Ignoring");
                return false;
            }
    
            // If we have a constraints changed intent in the queue don't add a second one. We are
            // treating this intent as special because every time a worker with constraints is complete
            // it kicks off an update for constraint proxies.
            if (CommandHandler.ACTION_CONSTRAINTS_CHANGED.equals(action)
                    && hasIntentWithAction(CommandHandler.ACTION_CONSTRAINTS_CHANGED)) {
                return false;
            }
    
            intent.putExtra(KEY_START_ID, startId);
            synchronized (mIntents) {
                boolean hasCommands = !mIntents.isEmpty();
                mIntents.add(intent);
                if (!hasCommands) {
                    // Only call processCommand if this is the first command.
                    // The call to dequeueAndCheckForCompletion will process the remaining commands
                    // in the order that they were added.
                    processCommand();
                }
            }
            return true;
        }
    
        private void processCommand() {
            assertMainThread();
            PowerManager.WakeLock processCommandLock =
                    WakeLocks.newWakeLock(mContext, PROCESS_COMMAND_TAG);
            try {
                processCommandLock.acquire();
                // Process commands on the background thread.
                mWorkManager.getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() {
                    @Override
                    public void run() {
                        synchronized (mIntents) {
                            mCurrentIntent = mIntents.get(0);
                        }
    
                        if (mCurrentIntent != null) {
                            final String action = mCurrentIntent.getAction();
                            final int startId = mCurrentIntent.getIntExtra(KEY_START_ID,
                                    DEFAULT_START_ID);
                            Logger.get().debug(TAG,
                                    String.format("Processing command %s, %s", mCurrentIntent,
                                            startId));
                            final PowerManager.WakeLock wakeLock = WakeLocks.newWakeLock(
                                    mContext,
                                    String.format("%s (%s)", action, startId));
                            try {
                                Logger.get().debug(TAG, String.format(
                                        "Acquiring operation wake lock (%s) %s",
                                        action,
                                        wakeLock));
    
                                wakeLock.acquire();
                                //等下下面我们就要分析
                                mCommandHandler.onHandleIntent(mCurrentIntent, startId,
                                        SystemAlarmDispatcher.this);
                            } catch (Throwable throwable) {
                                Logger.get().error(
                                        TAG,
                                        "Unexpected error in onHandleIntent",
                                        throwable);
                            }  finally {
                                Logger.get().debug(
                                        TAG,
                                        String.format(
                                                "Releasing operation wake lock (%s) %s",
                                                action,
                                                wakeLock));
                                wakeLock.release();
                                // Check if we have processed all commands
                                postOnMainThread(
                                        new DequeueAndCheckForCompletion(SystemAlarmDispatcher.this));
                            }
                        }
                    }
                });
            } finally {
                processCommandLock.release();
            }
        }
    

    mCommandHandler.onHandleIntentactionACTION_CONSTRAINTS_CHANGED

        void onHandleIntent(
                @NonNull Intent intent,
                int startId,
                @NonNull SystemAlarmDispatcher dispatcher) {
    
            String action = intent.getAction();
    
            if (ACTION_CONSTRAINTS_CHANGED.equals(action)) {
                handleConstraintsChanged(intent, startId, dispatcher);
            } else if (ACTION_RESCHEDULE.equals(action)) {
                handleReschedule(intent, startId, dispatcher);
            } else {
                Bundle extras = intent.getExtras();
                if (!hasKeys(extras, KEY_WORKSPEC_ID)) {
                    Logger.get().error(TAG,
                            String.format("Invalid request for %s, requires %s.",
                                    action,
                                    KEY_WORKSPEC_ID));
                } else {
                    if (ACTION_SCHEDULE_WORK.equals(action)) {
                        handleScheduleWorkIntent(intent, startId, dispatcher);
                    } else if (ACTION_DELAY_MET.equals(action)) {
                        handleDelayMet(intent, startId, dispatcher);
                    } else if (ACTION_STOP_WORK.equals(action)) {
                        handleStopWork(intent, dispatcher);
                    } else if (ACTION_EXECUTION_COMPLETED.equals(action)) {
                        handleExecutionCompleted(intent, startId);
                    } else {
                        Logger.get().warning(TAG, String.format("Ignoring intent %s", intent));
                    }
                }
            }
        }
    
        private void handleConstraintsChanged(
                @NonNull Intent intent, int startId,
                @NonNull SystemAlarmDispatcher dispatcher) {
    
            Logger.get().debug(TAG, String.format("Handling constraints changed %s", intent));
            // Constraints changed command handler is synchronous. No cleanup
            // is necessary.
            ConstraintsCommandHandler changedCommandHandler =
                    new ConstraintsCommandHandler(mContext, startId, dispatcher);
            changedCommandHandler.handleConstraintsChanged();
        }
    

    handleConstraintsChanged方法:

        @WorkerThread
        void handleConstraintsChanged() {
            List<WorkSpec> candidates = mDispatcher.getWorkManager().getWorkDatabase()
                    .workSpecDao()
                    .getScheduledWork();
    
            // Update constraint proxy to potentially disable proxies for previously
            // completed WorkSpecs.
            ConstraintProxy.updateAll(mContext, candidates);
    
            // This needs to be done to populate matching WorkSpec ids in every constraint controller.
            mWorkConstraintsTracker.replace(candidates);
    
            List<WorkSpec> eligibleWorkSpecs = new ArrayList<>(candidates.size());
            // Filter candidates should have already been scheduled.
            long now = System.currentTimeMillis();
            for (WorkSpec workSpec : candidates) {
                String workSpecId = workSpec.id;
                long triggerAt = workSpec.calculateNextRunTime();
                if (now >= triggerAt && (!workSpec.hasConstraints()
                        || mWorkConstraintsTracker.areAllConstraintsMet(workSpecId))) {
                    eligibleWorkSpecs.add(workSpec);
                }
            }
    
            for (WorkSpec workSpec : eligibleWorkSpecs) {
                String workSpecId = workSpec.id;
                Intent intent = CommandHandler.createDelayMetIntent(mContext, workSpecId);
                Logger.get().debug(TAG, String.format(
                        "Creating a delay_met command for workSpec with id (%s)", workSpecId));
                mDispatcher.postOnMainThread(
                        new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId));
            }
    
            mWorkConstraintsTracker.reset();
        }
    

    其中:

    //ConstraintsCommandHandler
    Intent intent = CommandHandler.createDelayMetIntent(mContext, workSpecId);
                Logger.get().debug(TAG, String.format(
                        "Creating a delay_met command for workSpec with id (%s)", workSpecId));
                mDispatcher.postOnMainThread(
                        new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId));
    

    创建一个actionACTION_DELAY_MET的Intent然后由SystemAlarmDispatcher发送出去,实际上也是调用了SystemAlarmDispatcher.add()方法,注意会回到SystemAlarmDispatcheradd()流程:

    当再次回到onHandleIntent()方法,在CommandHandler的onHandleIntent()方法中,actionACTION_DELAY_MET的执行是:

    // CommandHandler.java 类
    else if (ACTION_DELAY_MET.equals(action)) {
                        handleDelayMet(intent, startId, dispatcher);
                    } 
    

    handleDelayMet()的执行过程,会调用DelayMetCommandHandlerhandleProcessWork()方法,接着执行onAllConstraintsMet()

      @Override
        public void onAllConstraintsMet(@NonNull List<String> workSpecIds) {
            ... ...
            synchronized (mLock) {
                if (mCurrentState == STATE_INITIAL) {
                    
                    ... ...
                    boolean isEnqueued = mDispatcher.getProcessor().startWork(mWorkSpecId);
                    ... ...
                } else {
                    Logger.get().debug(TAG, String.format("Already started work for %s", mWorkSpecId));
                }
            }
        }
    

    mDispatcher.getProcessor() 查看

    public class SystemAlarmDispatcher implements ExecutionListener {
            //...
        private final Processor mProcessor;
            //...
        SystemAlarmDispatcher(
                @NonNull Context context,
                @Nullable Processor processor,
                @Nullable WorkManagerImpl workManager) {
    
            mContext = context.getApplicationContext();
            mCommandHandler = new CommandHandler(mContext);
            mWorkTimer = new WorkTimer();
            mWorkManager = workManager != null ? workManager : WorkManagerImpl.getInstance(context);
            mProcessor = processor != null ? processor : mWorkManager.getProcessor();
            mTaskExecutor = mWorkManager.getWorkTaskExecutor();
            mProcessor.addExecutionListener(this);
            // a list of pending intents which need to be processed
            mIntents = new ArrayList<>();
            // the current intent (command) being processed.
            mCurrentIntent = null;
            mMainHandler = new Handler(Looper.getMainLooper());
        }
            //...
        Processor getProcessor() {
            return mProcessor;
        }
        //...
    }    
    

    mProcessor = processor != null ? processor : mWorkManager.getProcessor() 这行,查看mWorkManager.getProcessor(),

    public class WorkManagerImpl extends WorkManager {
        //...
        private Processor mProcessor;
            //...
        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()));
            List<Scheduler> schedulers =
                    createSchedulers(applicationContext, configuration, workTaskExecutor);
            Processor processor = new Processor(
                    context,
                    configuration,
                    workTaskExecutor,
                    database,
                    schedulers);
            internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
        }
        //...
        private void internalInit(@NonNull Context context,
                @NonNull Configuration configuration,
                @NonNull TaskExecutor workTaskExecutor,
                @NonNull WorkDatabase workDatabase,
                @NonNull List<Scheduler> schedulers,
                @NonNull Processor processor) {
    
            context = context.getApplicationContext();
            mContext = context;
            mConfiguration = configuration;
            mWorkTaskExecutor = workTaskExecutor;
            mWorkDatabase = workDatabase;
            mSchedulers = schedulers;
            mProcessor = processor;
            mPreferenceUtils = new PreferenceUtils(workDatabase);
            mForceStopRunnableCompleted = false;
    
            // Check for direct boot mode
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && context.isDeviceProtectedStorage()) {
                throw new IllegalStateException("Cannot initialize WorkManager in direct boot mode");
            }
    
            // Checks for app force stops.
            mWorkTaskExecutor.executeOnBackgroundThread(new ForceStopRunnable(context, this));
        }
        //....
        
        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
        public @NonNull Processor getProcessor() {
            return mProcessor;
        }
    }    
    

    可以看到getProcessor() 返回的是mProcessor,而mProcessor是new Processor()的对象,那么执行startWork()的位置在Processor类中

    public class Processor implements ExecutionListener, ForegroundProcessor {
            public boolean startWork(@NonNull String id) {
            return startWork(id, null);
        }
    
        /**
         * Starts a given unit of work in the background.
         *
         * @param id The work id to execute.
         * @param runtimeExtras The {@link WorkerParameters.RuntimeExtras} for this work, if any.
         * @return {@code true} if the work was successfully enqueued for processing
         */
        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;
        }
    }    
    

    mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper) 执行 workWrapper,和之前一样,查看WorkWrapper.run

        //WorkWrapper 类
            @WorkerThread
        @Override
        public void run() {
            mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
            mWorkDescription = createWorkDescription(mTags);
            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);
                    mWorkDatabase.setTransactionSuccessful();
                    return;
                }
    
                // Do a quick check to make sure we don't need to bail out in case this work is already
                // running, finished, or is blocked.
                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;
                }
    
                // Case 1:
                // Ensure that Workers that are backed off are only executed when they are supposed to.
                // GreedyScheduler can schedule WorkSpecs that have already been backed off because
                // it is holding on to snapshots of WorkSpecs. So WorkerWrapper needs to determine
                // if the ListenableWorker is actually eligible to execute at this point in time.
    
                // Case 2:
                // On API 23, we double scheduler Workers because JobScheduler prefers batching.
                // So is the Work is periodic, we only need to execute it once per interval.
                // Also potential bugs in the platform may cause a Job to run more than once.
    
                if (mWorkSpec.isPeriodic() || mWorkSpec.isBackedOff()) {
                    long now = System.currentTimeMillis();
                    // Allow first run of a PeriodicWorkRequest
                    // to go through. This is because when periodStartTime=0;
                    // calculateNextRunTime() always > now.
                    // For more information refer to b/124274584
                    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));
                        // For AlarmManager implementation we need to reschedule this kind  of Work.
                        // This is not a problem for JobScheduler because we will only reschedule
                        // work if JobScheduler is unaware of a jobId.
                        resolve(true);
                        mWorkDatabase.setTransactionSuccessful();
                        return;
                    }
                }
    
                // Needed for nested transactions, such as when we're in a dependent work request when
                // using a SynchronousExecutor.
                mWorkDatabase.setTransactionSuccessful();
            } finally {
                mWorkDatabase.endTransaction();
            }
    
            // Merge inputs.  This can be potentially expensive code, so this should not be done inside
            // a database transaction.
            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);
            }
    
            final 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));
    
            // Not always creating a worker here, as the WorkerWrapper.Builder can set a worker override
            // in test mode.
            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();
    
            // Try to set the work to the running state.  Note that this may fail because another thread
            // may have modified the DB since we checked last at the top of this function.
            if (trySetRunning()) {
                if (tryCheckForInterruptionAndResolve()) {
                    return;
                }
    
                final SettableFuture<ListenableWorker.Result> future = SettableFuture.create();
                final WorkForegroundRunnable foregroundRunnable =
                        new WorkForegroundRunnable(
                                mAppContext,
                                mWorkSpec,
                                mWorker,
                                params.getForegroundUpdater(),
                                mWorkTaskExecutor
                        );
                mWorkTaskExecutor.getMainThreadExecutor().execute(foregroundRunnable);
    
                final ListenableFuture<Void> runExpedited = foregroundRunnable.getFuture();
                runExpedited.addListener(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            runExpedited.get();
                            Logger.get().debug(TAG,
                                    String.format("Starting work for %s", mWorkSpec.workerClassName));
                            // Call mWorker.startWork() on the main thread.
                            mInnerFuture = mWorker.startWork();
                            future.setFuture(mInnerFuture);
                        } catch (Throwable e) {
                            future.setException(e);
                        }
                    }
                }, mWorkTaskExecutor.getMainThreadExecutor());
    
                // Avoid synthetic accessors.
                final String workDescription = mWorkDescription;
                future.addListener(new Runnable() {
                    @Override
                    @SuppressLint("SyntheticAccessor")
                    public void run() {
                        try {
                            // If the ListenableWorker returns a null result treat it as a failure.
                            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();
            }
        }
    

    mInnerFuture = mWorker.startWork();

        // Worker。java类
        @WorkerThread
        public abstract @NonNull Result doWork();
    
       @Override
        public final @NonNull ListenableFuture<Result> startWork() {
            mFuture = SettableFuture.create();
            getBackgroundExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                     //此doWork函数 就是 看到曙光了
                        Result result = doWork();
                        mFuture.set(result);
                    } catch (Throwable throwable) {
                        mFuture.setException(throwable);
                    }
    
                }
            });
            return mFuture;
        }
    

    最后就又回到了我们自己写的work

    class UploadWorker(context: Context, workerParams: WorkerParameters) :
        Worker(context, workerParams) {
          
        private val TAG = UploadWorker::class.java.simpleName
        
        override fun doWork(): Result {
            Log.d(TAG, "doWork: run ... "); // 就答应了,我们自己写的任务的信息...
            return Result.success();
        }
    }
    

    相关文章

      网友评论

          本文标题:WorkMananger

          本文链接:https://www.haomeiwen.com/subject/chczhdtx.html