WorkManager基本使用及源码分析(二) - WorkManagerInitializer

2021年02月06日 99 字 Jetpack


目录


源码篇

上一篇中我们简单使用了WorkManager的一般功能,基础使用还是比较简单的。“WorkManager 是一个 API,可供您轻松调度那些即使在退出应用或重启设备后仍应运行的可延期异步任务”。那么我们来了解一下他到底是怎么工作的吧。

2.1 AndroidManifest

秉承看三方库源码的一般习惯,先从AndroidManifest.xml文件看起,我们知道一般的,想要了解一个库的主要组成就要想了解一个App一样首先要了解它有哪些组件构成,而库的AndroidManifest文件一般都会合并至应用AndroidManifest.xml中,且一般的需要初始化的库,常规的初始化方案是使用ContentProvider尽早地初始化且减少代码侵入,对这种方式不了解的,请参见Android-使用ContentProvider来初始化你的sdk系列文章。

废话不多说,让我们来看看work-runtime库的AndroidManifest.xml有哪些玄机。

work-runtime库的AndroidManifest.xml我们可以在AndroidStudio的 Project窗口中External Libraries栏目中查找”work-runtime”即可看到WorkManager的aar包结构和内容。打开AndroidManefest.xml我们发现以下重要组件:

  • androidx.work.impl.WorkManagerInitializer
  • androidx.work.impl.background.systemalarm.SystemAlarmService
  • androidx.work.impl.background.systemjob.SystemJobService
  • androidx.work.impl.foreground.SystemForegroundService
  • androidx.work.impl.utils.ForceStopRunnable$BroadcastReceiver
  • androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy
  • androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy
  • androidx.work.impl.background.systemalarm.ConstraintProxy$StorageNotLowProxy
  • androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy
  • androidx.work.impl.background.systemalarm.RescheduleReceiver
  • androidx.work.impl.background.systemalarm.ConstraintProxyUpdateReceiver
  • androidx.work.impl.diagnostics.DiagnosticsReceiver

我们可以大胆猜测: WorkManager使用ContentProvider WorkManagerInitializer执行初始化操作, 通过Service管理任务执行及状态,通过BroadcastReceiver掌握任务执行时机和条件。

WorkManagerInitializer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* The {@link ContentProvider} responsible for initializing {@link WorkManagerImpl}.
* // 机翻:负责初始化{@link WorkManagerImpl}的{@link ContentProvider}。
* @hide // 隐藏API,对调用者不可见
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class WorkManagerInitializer extends ContentProvider {
@Override
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
// 机翻:使用默认配置初始化WorkManager。
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}
// ... 省略其他无关代码
}

WorkManager.initialize -> WorkManagerImpl.initialize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// {@link WorkManagerImpl#initialize}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
// ... 重复创建检查,若被多次调用此创建方法则抛错WorkManager is already initialized.
if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
sDefaultInstance = new WorkManagerImpl(
context, configuration,
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}

代码中configuration.getTaskExecutor()最终调用方法为:

1
2
3
4
5
6
private @NonNull Executor createDefaultExecutor() {
return Executors.newFixedThreadPool(
// This value is the same as the core pool size for AsyncTask#THREAD_POOL_EXECUTOR.
// 机翻:这个值与AsyncTask#THREAD_POOL_EXECUTOR的核心池大小相同。
Math.max(2, Math.min(Runtime.getRuntime().availableProcessors() - 1, 4)));
}

备注:一般地,AsyncTask里线程池核心线程数为CPU + 1,最大线程数为CPU * 2 + 1

纵观代码,我们发现WorkManagerInitializer就是一个负责初始化WorkManager的ContentProvider,职责单一,简单明了。
WorkManager.initialize()最终使用ContentProvider上下文对象context、默认configuration及线程池容量与AsyncTask核心线程数一致的Executor创建了WorkManagerImpl单例实例。