上一篇讲解了WorkManager使用篇,本篇我们就从源码角度来分析WorkManager的工作原理。
WorkManager的原理
上一篇WorkManager使用篇讲解了如何使用WorkManager。本篇我们就按照上一篇的使用步骤来分析源码。
生成WorkRequest的源码
- 第一步生成一个待执行的request请求
val request = OneTimeWorkRequestBuilder<CountWorker>() .setConstraints(constraints) .addTag("tagCountWorker") .setInputData(Data.Builder().putString("parameter1", "value of parameter1").build()) .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.HOURS) .build()
- 我们看类WorkRequest的源码部分:
public abstract class WorkRequest { private @NonNull UUID mId; private @NonNull WorkSpec mWorkSpec; private @NonNull Set<String> mTags; public abstract static class Builder<B extends Builder<?, ?>, W extends WorkRequest> { boolean mBackoffCriteriaSet = false; UUID mId; WorkSpec mWorkSpec; Set<String> mTags = new HashSet<>(); Class<? extends ListenableWorker> mWorkerClass; Builder(@NonNull Class<? extends ListenableWorker> workerClass) { mId = UUID.randomUUID(); mWorkerClass = workerClass; mWorkSpec = new WorkSpec(mId.toString(), workerClass.getName()); addTag(workerClass.getName()); } public final @NonNull W build() { W returnValue = buildInternal(); // Create a new id and WorkSpec so this WorkRequest.Builder can be used multiple times. mId = UUID.randomUUID(); mWorkSpec = new WorkSpec(mWorkSpec); mWorkSpec.id = mId.toString(); return returnValue; } abstract @NonNull W buildInternal(); abstract @NonNull B getThis(); } }
- 它采用了建造者设计模式,内部成员变量
mWorkSpec
使用的是Room数据库,可以持久化存储,除非被clear data,所以能保证系统即使被重启,也可以确保任务得到执行。我们查看WorkSpec
的源码:
@Entity( indices = { @Index(value = {"schedule_requested_at"}), @Index(value = {"period_start_time"}) } ) public final class WorkSpec { private static final String TAG = Logger.tagWithPrefix("WorkSpec"); public static final long SCHEDULE_NOT_REQUESTED_YET = -1; @ColumnInfo(name = "id") @PrimaryKey @NonNull public String id; @ColumnInfo(name = "state") @NonNull public WorkInfo.State state = ENQUEUED; @ColumnInfo(name = "worker_class_name") @NonNull public String workerClassName; @ColumnInfo(name = "input_merger_class_name") public String inputMergerClassName; @ColumnInfo(name = "input") @NonNull public Data input = Data.EMPTY; @ColumnInfo(name = "output") @NonNull public Data output = Data.EMPTY; @ColumnInfo(name = "initial_delay") public long initialDelay; @ColumnInfo(name = "interval_duration") public long intervalDuration; @ColumnInfo(name = "flex_duration") public long flexDuration; @Embedded @NonNull public Constraints constraints = Constraints.NONE; @ColumnInfo(name = "run_attempt_count") @IntRange(from = 0) public int runAttemptCount; @ColumnInfo(name = "backoff_policy") @NonNull public BackoffPolicy backoffPolicy = BackoffPolicy.EXPONENTIAL; @ColumnInfo(name = "backoff_delay_duration") public long backoffDelayDuration = WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS; @ColumnInfo(name = "period_start_time") public long periodStartTime; @ColumnInfo(name = "minimum_retention_duration") public long minimumRetentionDuration; @ColumnInfo(name = "schedule_requested_at") public long scheduleRequestedAt = SCHEDULE_NOT_REQUESTED_YET; /** * This is {@code true} when the WorkSpec needs to be hosted by a foreground service. */ @ColumnInfo(name = "run_in_foreground") public boolean runInForeground; public WorkSpec(@NonNull String id, @NonNull String workerClassName) { this.id = id; this.workerClassName = workerClassName; } public WorkSpec(@NonNull WorkSpec other) { id = other.id; workerClassName = other.workerClassName; state = other.state; inputMergerClassName = other.inputMergerClassName; input = new Data(other.input); output = new Data(other.output); initialDelay = other.initialDelay; intervalDuration = other.intervalDuration; flexDuration = other.flexDuration; constraints = new Constraints(other.constraints); runAttemptCount = other.runAttemptCount; backoffPolicy = other.backoffPolicy; backoffDelayDuration = other.backoffDelayDuration; periodStartTime = other.periodStartTime; minimumRetentionDuration = other.minimumRetentionDuration; scheduleRequestedAt = other.scheduleRequestedAt; runInForeground = other.runInForeground; } }
- 我们看到上面使用了Room的
Entity
注解来注解WorkSpec
,说明这是一个持有化存储的类,会被存储在数据库中。它里面存储了一个WorkRequest的几乎所有信息,包括唯一标识id
,workerClassName
,input
,output
,constraints
等,这些信息在我们生成WorkRequest中都有涉及。
- 它采用了建造者设计模式,内部成员变量
WorkManager.getInstance(this)源码
- WorkManager是一个抽象类,它的实现类是
WorkManagerImpl
,采用单例模式返回WorkManagerImpl
对象。下面注释1的地方调用getInstance
其实返回值已经不为空了,下面我们来分析:public static @NonNull WorkManager getInstance(@NonNull Context context) { return WorkManagerImpl.getInstance(context); } @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) { synchronized (sLock) { //-----1----- WorkManagerImpl instance = getInstance(); if (instance == null) { Context appContext = context.getApplicationContext(); if (appContext instanceof Configuration.Provider) { initialize( appContext, ((Configuration.Provider) appContext).getWorkManagerConfiguration()); instance = getInstance(appContext); } else { throw new IllegalStateException("WorkManager is not initialized properly. You " + "have explicitly disabled WorkManagerInitializer in your manifest, " + "have not manually called WorkManager#initialize at this point, and " + "your Application does not implement Configuration.Provider."); } } return instance; } }
getInstance
源码如下,我们看到有两个WorkManagerImpl
对象,这里sDelegatedInstance
已经不为空,它是在哪里赋值的呢?private static WorkManagerImpl sDelegatedInstance = null; private static WorkManagerImpl sDefaultInstance = null; @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public static @Nullable WorkManagerImpl getInstance() { synchronized (sLock) { if (sDelegatedInstance != null) { return sDelegatedInstance; } return sDefaultInstance; } }
- 在源码中有这么一个类
WorkManagerInitializer
,它继承ContentProvider
,源码如下:@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public class WorkManagerInitializer extends ContentProvider { @Override public boolean onCreate() { // Initialize WorkManager with the default configuration. WorkManager.initialize(getContext(), new Configuration.Builder().build()); return true; } }
- 我们都知道
ContentProvider
的创建时机是在程序的入口ActivityThread.main
中,通过调用thread.attach
最终回调到activityThread.handleBindApplication
方法,在这个方法中ActivityThread会创建Application对象并加载ContentProvider,但是有一点要注意,就是会先加载ContentProvider然后在调用Application的onCreate方法
。 - 这样在程序启动前就会调用WorkManagerInitializer的onCreate方法,从而调用WorkManager的initialize方法,我们来看一下这个方法:
public boolean onCreate() { // Initialize WorkManager with the default configuration. //-----1----- WorkManager.initialize(getContext(), new Configuration.Builder().build()); return true; } public static void initialize(@NonNull Context context, @NonNull Configuration configuration) { WorkManagerImpl.initialize(context, configuration); } @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) { //-----2----- sDefaultInstance = new WorkManagerImpl( context, configuration, new WorkManagerTaskExecutor(configuration.getTaskExecutor())); } sDelegatedInstance = sDefaultInstance; } } }
- 在注释1的地方,传入了一个参数
Configuration
, 下面我们先来看一下Configuration
的源码:public final class Configuration { public static final int MIN_SCHEDULER_LIMIT = 20; final @NonNull Executor mExecutor; final @NonNull Executor mTaskExecutor; final @NonNull WorkerFactory mWorkerFactory; final @NonNull InputMergerFactory mInputMergerFactory; final int mLoggingLevel; final int mMinJobSchedulerId; final int mMaxJobSchedulerId; final int mMaxSchedulerLimit; private final boolean mIsUsingDefaultTaskExecutor; Configuration(@NonNull Configuration.Builder builder) { if (builder.mExecutor == null) { mExecutor = createDefaultExecutor(); } else { mExecutor = builder.mExecutor; } if (builder.mTaskExecutor == null) { mIsUsingDefaultTaskExecutor = true; mTaskExecutor = createDefaultExecutor(); } else { mIsUsingDefaultTaskExecutor = false; mTaskExecutor = builder.mTaskExecutor; } if (builder.mWorkerFactory == null) { mWorkerFactory = WorkerFactory.getDefaultWorkerFactory(); } else { mWorkerFactory = builder.mWorkerFactory; } if (builder.mInputMergerFactory == null) { mInputMergerFactory = InputMergerFactory.getDefaultInputMergerFactory(); } else { mInputMergerFactory = builder.mInputMergerFactory; } mLoggingLevel = builder.mLoggingLevel; mMinJobSchedulerId = builder.mMinJobSchedulerId; mMaxJobSchedulerId = builder.mMaxJobSchedulerId; mMaxSchedulerLimit = builder.mMaxSchedulerLimit; } }
- 我们截取了
Configuration
部分重要的源码,它是采用的建造者模式,从上面的源码看出,它是一个配置类,里面保存了很多配置信息,比如Executor
,WorkerFactory
,InputMergerFactory
等,这里的Executor
默认是一个采用Executors.newFixedThreadPool
的线程池。 - 然后我们接着看上面注释2的地方使用构造方法初始化了
sDefaultInstance
,并将其赋值给了sDelegatedInstance
,所以程序在一开始就初始化了这两个对象,当我们调用的时候就不为空了。我们看内部实现:sDefaultInstance = new WorkManagerImpl( context, configuration, //-----1----- new WorkManagerTaskExecutor(configuration.getTaskExecutor())); public WorkManagerImpl( @NonNull Context context, @NonNull Configuration configuration, @NonNull TaskExecutor workTaskExecutor) { this(context, configuration, workTaskExecutor, //-----2----- context.getResources().getBoolean(R.bool.workmanager_test_configuration)); } public WorkManagerImpl( @NonNull Context context, @NonNull Configuration configuration, @NonNull TaskExecutor workTaskExecutor, boolean useTestDatabase) { this(context, configuration, workTaskExecutor, //-----3----- WorkDatabase.create( context.getApplicationContext(), workTaskExecutor.getBackgroundExecutor(), useTestDatabase) ); } 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())); //-----4----- List<Scheduler> schedulers = createSchedulers(applicationContext, workTaskExecutor); /-----5----- Processor processor = new Processor( context, configuration, workTaskExecutor, database, schedulers); //-----6----- internalInit(context, configuration, workTaskExecutor, database, schedulers, processor); }
- 注释1处提供了一个新的类
WorkManagerTaskExecutor
,它内部提供了主线程和子线程切换以及执行的操作。 - 注释2配置了一个标志位,用来标记是否采用测试数据库,后面会使用到这个参数。
- 注释3就开始创建数据库
WorkDatabase
,它的源码如下,我们看到如果useTestDatabase
为true的话,就会采用Room.inMemoryDatabaseBuilder
创建数据库,并且允许在主线程查询。对Room的使用可以参考Room使用篇。
@Database(entities = { Dependency.class, WorkSpec.class, WorkTag.class, SystemIdInfo.class, WorkName.class, WorkProgress.class, Preference.class}, version = 10) @TypeConverters(value = {Data.class, WorkTypeConverters.class}) public abstract class WorkDatabase extends RoomDatabase { ... } public static WorkDatabase create( @NonNull final Context context, @NonNull Executor queryExecutor, boolean useTestDatabase) { RoomDatabase.Builder<WorkDatabase> builder; if (useTestDatabase) { builder = Room.inMemoryDatabaseBuilder(context, WorkDatabase.class) .allowMainThreadQueries(); } else { String name = WorkDatabasePathHelper.getWorkDatabaseName(); builder = Room.databaseBuilder(context, WorkDatabase.class, name); builder.openHelperFactory(new SupportSQLiteOpenHelper.Factory() { @NonNull @Override public SupportSQLiteOpenHelper create( @NonNull SupportSQLiteOpenHelper.Configuration configuration) { SupportSQLiteOpenHelper.Configuration.Builder configBuilder = SupportSQLiteOpenHelper.Configuration.builder(context); configBuilder.name(configuration.name) .callback(configuration.callback) .noBackupDirectory(true); FrameworkSQLiteOpenHelperFactory factory = new FrameworkSQLiteOpenHelperFactory(); return factory.create(configBuilder.build()); } }); } }
- 注释1处提供了一个新的类
- 注释4处调用了
createSchedulers
来创建一个Scheduler的List,后面会使用到。public List<Scheduler> createSchedulers( @NonNull Context context, @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, taskExecutor, this)); }
- 注释5处创建了一个
Process
对象,官方的解释是它可以根据需要智能地调度和执行工作,完美看到它几乎把所有的配置信息都保存在对象中,包括配置configuration
,workTaskExecutor
, 数据库database
,调度schedulers
.。 - 注释6处就是将上面创建的对象赋值到
WorkManagerImpl
成员变量中,到此处WorkManager.getInstance(context)
创建实例的过程就结束了。
enqueue(request)源码分析
- enqueue实际调用的是
WorkContinuationImpl
的enqueue方法,源码如下:
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.
//-----1-----
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;
}
- 在注释1的地方生成了一个
EnqueueRunnable
,它继承Runnable,然后通过之前在Configuration
中创建的线程池,将EnqueueRunnable加入到线程池中执行,返回一个Operation
对象。我们关注一下EnqueueRunnable
的run方法:
public class EnqueueRunnable implements Runnable {
private static final String TAG = Logger.tagWithPrefix("EnqueueRunnable");
private final WorkContinuationImpl mWorkContinuation;
private final OperationImpl mOperation;
public EnqueueRunnable(@NonNull WorkContinuationImpl workContinuation) {
mWorkContinuation = workContinuation;
mOperation = new OperationImpl();
}
@Override
public void run() {
try {
if (mWorkContinuation.hasCycles()) {
throw new IllegalStateException(
String.format("WorkContinuation has cycles (%s)", mWorkContinuation));
}
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);
//-----1-----
scheduleWorkInBackground();
}
mOperation.setState(Operation.SUCCESS);
} catch (Throwable exception) {
mOperation.setState(new Operation.State.FAILURE(exception));
}
}
public Operation getOperation() {
return mOperation;
}
}
- 我们关注注释1处的
scheduleWorkInBackground
方法:public void scheduleWorkInBackground() { WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl(); Schedulers.schedule( workManager.getConfiguration(), workManager.getWorkDatabase(), workManager.getSchedulers()); } 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> eligibleWorkSpecs; workDatabase.beginTransaction(); try { eligibleWorkSpecs = workSpecDao.getEligibleWorkForScheduling( configuration.getMaxSchedulerLimit()); if (eligibleWorkSpecs != null && eligibleWorkSpecs.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 : eligibleWorkSpecs) { workSpecDao.markWorkSpecScheduled(workSpec.id, now); } } workDatabase.setTransactionSuccessful(); } finally { workDatabase.endTransaction(); } if (eligibleWorkSpecs != null && eligibleWorkSpecs.size() > 0) { WorkSpec[] eligibleWorkSpecsArray = eligibleWorkSpecs.toArray(new WorkSpec[0]); // Delegate to the underlying scheduler. for (Scheduler scheduler : schedulers) { //-----1----- scheduler.schedule(eligibleWorkSpecsArray); } } }
- 在注释1处调用了
scheduler.schedule
方法,我们前面将GreedyScheduler
加入到队列中,我们这里主要分析该类:public void schedule(@NonNull WorkSpec... workSpecs) { if (mIsMainProcess == null) { // The default process name is the package name. mIsMainProcess = TextUtils.equals(mContext.getPackageName(), getProcessName()); } if (!mIsMainProcess) { Logger.get().info(TAG, "Ignoring schedule request in non-main process"); return; } registerExecutionListenerIfNeeded(); List<WorkSpec> constrainedWorkSpecs = new ArrayList<>(); List<String> constrainedWorkSpecIds = new ArrayList<>(); for (WorkSpec workSpec : workSpecs) { //-----1----- if (workSpec.state == WorkInfo.State.ENQUEUED && !workSpec.isPeriodic() && workSpec.initialDelay == 0L && !workSpec.isBackedOff()) { 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)); //-----2----- mWorkManagerImpl.startWork(workSpec.id); } } } synchronized (mLock) { if (!constrainedWorkSpecs.isEmpty()) { Logger.get().debug(TAG, String.format("Starting tracking for [%s]", TextUtils.join(",", constrainedWorkSpecIds))); mConstrainedWorkSpecs.addAll(constrainedWorkSpecs); mWorkConstraintsTracker.replace(mConstrainedWorkSpecs); } } }
- 首先在注释1处判断是否有约束条件,有的话将其任务和任务id加入到集合中,没有的话直接执行注释2处的
startWork
方法。我们先关注没有约束条件时候的startWork
方法:public void startWork( @NonNull String workSpecId, @Nullable WorkerParameters.RuntimeExtras runtimeExtras) { mWorkTaskExecutor .executeOnBackgroundThread( new StartWorkRunnable(this, workSpecId, runtimeExtras)); }
- 接着通过线程池调用了
StartWorkRunnable
,它是一个Runnable:public class StartWorkRunnable implements Runnable { private WorkManagerImpl mWorkManagerImpl; private String mWorkSpecId; private WorkerParameters.RuntimeExtras mRuntimeExtras; public StartWorkRunnable( WorkManagerImpl workManagerImpl, String workSpecId, WorkerParameters.RuntimeExtras runtimeExtras) { mWorkManagerImpl = workManagerImpl; mWorkSpecId = workSpecId; mRuntimeExtras = runtimeExtras; } @Override public void run() { //-----1----- mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras); } }
- 接着上面注释1处的
getProcessor().startWork
方法,Processor的startWorker源码如下: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 (mEnqueuedWorkMap.containsKey(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); } //-----1----- mWorkTaskExecutor.getBackgroundExecutor().execute(workWrapper); Logger.get().debug(TAG, String.format("%s: processing %s", getClass().getSimpleName(), id)); return true; }
- 它是一个work的包装类WorkWrapper,然后执行注释1处的方法, 我们看
WorkWrapper
的源码:public class WorkerWrapper implements Runnable { public void run() { mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId); mWorkDescription = createWorkDescription(mTags); runWorker(); } private void runWorker() { ... if (mWorker == null) { //-----1----- mWorker = mConfiguration.getWorkerFactory().createWorkerWithDefaultFallback( mAppContext, mWorkSpec.workerClassName, params); } mWorkTaskExecutor.getMainThreadExecutor() .execute(new Runnable() { @Override public void run() { try { Logger.get().debug(TAG, String.format("Starting work for %s", mWorkSpec.workerClassName)); //-----2----- mInnerFuture = mWorker.startWork(); future.setFuture(mInnerFuture); } catch (Throwable e) { future.setException(e); } } }); } }
- 在注释1处通过类名,采用反射机制获取到ListenableWorker对象。其中Worker类继承自ListenableWorker类。
- 注释2调用ListenableWorker.startWork,它实际上是调用Worker类的startWork方法,Worker的源码如下:
public abstract class Worker extends ListenableWorker { public abstract @NonNull Result doWork(); @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; } }
- 上面我们看到
startWork
方法实际上调用的是我们自己实现的doWork
方法,到这里终于调用了我们需要的逻辑。
有约束Constraints的任务是如何被执行的?
- 我反编译了我的apk,拿到了
androidManifest.xml
:<provider //-----1----- android:name="androidx.work.impl.WorkManagerInitializer" android:authorities="com.oman.forward.workmanager-init" android:directBootAware="false" android:exported="false" android:multiprocess="true" /> <service android:name="androidx.work.impl.background.systemalarm.SystemAlarmService" android:directBootAware="false" android:enabled="@bool/enable_system_alarm_service_default" android:exported="false" /> <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" /> <service android:name="androidx.work.impl.foreground.SystemForegroundService" android:directBootAware="false" android:enabled="@bool/enable_system_foreground_service_default" android:exported="false" /> <receiver android:name="androidx.work.impl.utils.ForceStopRunnable$BroadcastReceiver" android:directBootAware="false" android:enabled="true" android:exported="false" /> <receiver android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy" android:directBootAware="false" android:enabled="false" android:exported="false"> <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"> <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"> <intent-filter> <action android:name="android.intent.action.DEVICE_STORAGE_LOW" /> <action android:name="android.intent.action.DEVICE_STORAGE_OK" /> </intent-filter> </receiver> <receiver //-----2----- android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy" android:directBootAware="false" android:enabled="false" android:exported="false"> <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"> <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"> <intent-filter> <action android:name="androidx.work.impl.background.systemalarm.UpdateProxies" /> </intent-filter> </receiver> <service android:name="androidx.room.MultiInstanceInvalidationService" android:exported="false" /> <provider android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer" android:authorities="com.oman.forward.lifecycle-process" android:exported="false" android:multiprocess="true" />
- 在最开始注释1的地方有一个provider,正是我们分析初始化workManager的时候的那个Provider。
- 而且我们还看到有很多的
Receiver
,我们以注释2处的NetworkStateProxy
为例进行分析,它有一个action是CONNECTIVITY_CHANGE
,所以当网络状态发生变化的时候会触发这个Receiver。我们看源码部分:
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)); //-----1----- Intent constraintChangedIntent = CommandHandler.createConstraintsChangedIntent(context); context.startService(constraintChangedIntent); } /** * Proxy for Battery Not Low constraint */ public static class BatteryNotLowProxy extends ConstraintProxy { } /** * Proxy for Battery Charging constraint */ public static class BatteryChargingProxy extends ConstraintProxy { } /** * Proxy for Storage Not Low constraint */ public static class StorageNotLowProxy extends ConstraintProxy { } /** * Proxy for Network State constraints */ public static class NetworkStateProxy extends ConstraintProxy { } }
- 当网络状态发生变化的时候会执行上面注释1的
CommandHandler的createConstraintsChangedIntent(context)
方法,源码如下:
static final String ACTION_CONSTRAINTS_CHANGED = "ACTION_CONSTRAINTS_CHANGED"; static Intent createConstraintsChangedIntent(@NonNull Context context) { Intent intent = new Intent(context, SystemAlarmService.class); intent.setAction(ACTION_CONSTRAINTS_CHANGED); return intent; }
- 这里启动了一个
SystemAlarmService
,它是一个Service,我们关注它的onStartCommand
方法:
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) { mDispatcher.add(intent, startId); } // If the service were to crash, we want all unacknowledged Intents to get redelivered. return Service.START_REDELIVER_INTENT; }
- 调用了
mDispatcher.add(intent, startId)
方法:
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 (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(); //-----1----- 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. //-----2----- processCommand(); } } return true; }
- 注释1处将intent添加到了
mIntents
中,注释2处调用了processCommand
方法:
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) { //-----1----- 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(); //-----2----- 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(); } }
- 上面注释1得到了之前加入的Intent。在注释2处调用了
mCommandHandler.onHandleIntent
:
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)); } } } }
- 在这个方法中会判断传入进来的action,进行相应的方法调用。因为这里的action是
ACTION_CONSTRAINTS_CHANGED
,所以会执行注释1处的handleConstraintsChanged
方法:
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); //-----1----- changedCommandHandler.handleConstraintsChanged(); }
- 调用了上面注释1处的
changedCommandHandler.handleConstraintsChanged()
方法,源码如下:
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; //-----1----- 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( //-----2----- new SystemAlarmDispatcher.AddRunnable(mDispatcher, intent, mStartId)); } mWorkConstraintsTracker.reset(); }
- 注释1处创建了一个action为
ACTION_DELAY_MET
的Intent。 - 注释2处将这个intent加入到一个Runnable中,将这个Runnable切换到主线程执行。
AddRunnable
的源码如下:
static class AddRunnable implements Runnable { private final SystemAlarmDispatcher mDispatcher; private final Intent mIntent; private final int mStartId; AddRunnable(@NonNull SystemAlarmDispatcher dispatcher, @NonNull Intent intent, int startId) { mDispatcher = dispatcher; mIntent = intent; mStartId = startId; } @Override public void run() { mDispatcher.add(mIntent, mStartId); } }
- 我们看到又调用了
mDispatcher.add
方法,最终还是会 ->processCommand
->mCommandHandler.onHandleIntent
, 但是这时候在onHandleIntent
中的action就不是ACTION_CONSTRAINTS_CHANGED
,而是ACTION_DELAY_MET
了,所以要执行handleDelayMet
方法:
private void handleDelayMet( @NonNull Intent intent, int startId, @NonNull SystemAlarmDispatcher dispatcher) { Bundle extras = intent.getExtras(); synchronized (mLock) { String workSpecId = extras.getString(KEY_WORKSPEC_ID); Logger.get().debug(TAG, String.format("Handing delay met for %s", workSpecId)); // Check to see if we are already handling an ACTION_DELAY_MET for the WorkSpec. // If we are, then there is nothing for us to do. if (!mPendingDelayMet.containsKey(workSpecId)) { DelayMetCommandHandler delayMetCommandHandler = new DelayMetCommandHandler(mContext, startId, workSpecId, dispatcher); mPendingDelayMet.put(workSpecId, delayMetCommandHandler); //-----1----- delayMetCommandHandler.handleProcessWork(); } else { Logger.get().debug(TAG, String.format("WorkSpec %s is already being handled for ACTION_DELAY_MET", workSpecId)); } } }
- 在注释1处调用了
delayMetCommandHandler.handleProcessWork()
方法,如下:
void handleProcessWork() { mWakeLock = WakeLocks.newWakeLock( mContext, String.format("%s (%s)", mWorkSpecId, mStartId)); Logger.get().debug(TAG, String.format("Acquiring wakelock %s for WorkSpec %s", mWakeLock, mWorkSpecId)); mWakeLock.acquire(); WorkSpec workSpec = mDispatcher.getWorkManager() .getWorkDatabase() .workSpecDao() .getWorkSpec(mWorkSpecId); // This should typically never happen. Cancelling work should remove alarms, but if an // alarm has already fired, then fire a stop work request to remove the pending delay met // command handler. if (workSpec == null) { stopWork(); return; } // Keep track of whether the WorkSpec had constraints. This is useful for updating the // state of constraint proxies when onExecuted(). mHasConstraints = workSpec.hasConstraints(); if (!mHasConstraints) { Logger.get().debug(TAG, String.format("No constraints for %s", mWorkSpecId)); onAllConstraintsMet(Collections.singletonList(mWorkSpecId)); } else { // Allow tracker to report constraint changes //-----1----- mWorkConstraintsTracker.replace(Collections.singletonList(workSpec)); } }
- 因为有约束条件,所以会进入注释1处的
replace
方法:
* * @param workSpecs A list of {@link WorkSpec}s to monitor constraints for */ @SuppressWarnings("unchecked") public void replace(@NonNull Iterable<WorkSpec> workSpecs) { synchronized (mLock) { for (ConstraintController<?> controller : mConstraintControllers) { controller.setCallback(null); } for (ConstraintController<?> controller : mConstraintControllers) { //-----1----- controller.replace(workSpecs); } for (ConstraintController<?> controller : mConstraintControllers) { controller.setCallback(this); } } } public void replace(@NonNull Iterable<WorkSpec> workSpecs) { mMatchingWorkSpecIds.clear(); for (WorkSpec workSpec : workSpecs) { if (hasConstraint(workSpec)) { mMatchingWorkSpecIds.add(workSpec.id); } } if (mMatchingWorkSpecIds.isEmpty()) { mTracker.removeListener(this); } else { mTracker.addListener(this); } //-----2----- updateCallback(mCallback, mCurrentValue); }
- 紧接着调用了注释1处的
replace
到注释2处的updateCallback
:
private void updateCallback( @Nullable OnConstraintUpdatedCallback callback, @Nullable T currentValue) { // We pass copies of references (callback, currentValue) to updateCallback because public // APIs on ConstraintController may be called from any thread, and onConstraintChanged() is // called from the main thread. if (mMatchingWorkSpecIds.isEmpty() || callback == null) { return; } if (currentValue == null || isConstrained(currentValue)) { callback.onConstraintNotMet(mMatchingWorkSpecIds); } else { //-----1----- callback.onConstraintMet(mMatchingWorkSpecIds); } }
- 接着调用到了注释1处的
onConstraintMet
方法。接着会执行到GreedyScheduler
的onAllConstraintsMet方法中:
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); } }
- 到这里,就会发现开始执行
mWorkManagerImpl.startWork
方法了:
public void startWork( @NonNull String workSpecId, @Nullable WorkerParameters.RuntimeExtras runtimeExtras) { mWorkTaskExecutor .executeOnBackgroundThread( new StartWorkRunnable(this, workSpecId, runtimeExtras)); }
- 这里的
StartWorkRunnable
就和前面分析的连接上了,最终会调用我们自定义的doWork
方法。