-
Notifications
You must be signed in to change notification settings - Fork 116
WorkManager的实现原理
WorkManager的实现原理
WorkManager是Android jetpack提供执行后台任务的管理组件。使用WorkManager运行的任务,即使退出杀掉APP,也可以保证任务能够正常执行。 如果应用正在运行时执行任务,WorkManager可以在新线程中执行,如果应用为运行,WorkManager会选择一种合适的方式来执行后台任务。使用哪种方式取决于API和包依赖项。WorkManager可能会使用JobScheduler,Firebase JobDispatcher或者AlarmManager
确保重要的后台任务一定会执行(非及时性的任务,如上传日志、同步数据等)
1.编写执行任务的Worker
public class MainWorker1 extends Worker {
private final static String TAG = MainWorker1.class.getSimpleName();
public MainWorker1(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
// 后台任务 并且 异步的
@NonNull
@Override
public Result doWork() {
Log.d(TAG, "MainWorker1 doWork: run started ... ");
try {
Thread.sleep(8000); // 睡眠
} catch (InterruptedException e) {
e.printStackTrace();
return Result.failure(); // 本次任务失败
} finally {
Log.d(TAG, "MainWorker1 doWork: run end ... ");
}
return Result.success(); // 本次任务成功
}
}
2.执行任务
OneTimeWorkRequest oneTimeWorkRequest =
new OneTimeWorkRequest.Builder(MainWorker1.class).build();
WorkManager.getInstance(this).enqueue(oneTimeWorkRequest);
3.添加约束条件
// 约束条件,必须满足条件,才能执行后台任务 (在连接网络,插入电源 并且 处于空闲时)
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // 网络链接中...
/*.setRequiresCharging(true) // 充电中..
.setRequiresDeviceIdle(true) // 空闲时.. (例如:你没有玩游戏,你没有看片)*/
.build();
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(MainWorker3.class)
.setConstraints(constraints) // Request关联 约束条件
.build();
// 加入队列
WorkManager.getInstance(this).enqueue(request);
4.执行周期任务 OneTimeWorkRequest的任务只能执行一次,如果是周期性的任务可以使用 PeriodicWorkRequest。
// 制定一个每隔1小时执行一次的Request
PeriodicWorkRequest periodicWorkRequest
= new PeriodicWorkRequest.Builder(MainWorker3.class, 1, TimeUnit.HOURS).build();
// 监听状态
WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.getId())
.observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(WorkInfo workInfo) {
Log.d(MainWorker2.TAG, "状态:" + workInfo.getState().name()); // 这里只会是状态只会是ENQUEUE,因为是周期任务。
if (workInfo.getState().isFinished()) {
Log.d(MainWorker2.TAG, "状态:isFinished=true 后台任务已经完成了...");
}
}
});
WorkManager.getInstance(this).enqueue(periodicWorkRequest);
WorkManager会将任务保存到Room数据库中,系统通过JobScheduler或者AlarmManager来执行。
1.WorkManager会在清单文件中生成一个ContentProvider,在第一次打开APP的时候便会执行WorkManager.getInstance进行单利的初始化工作。
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:exported="false"
android:multiprocess="true"
android:authorities="com.zhangpan.myapplication.workmanager-init"
android:directBootAware="false" />
public class WorkManagerInitializer extends ContentProvider {
@Override
public boolean onCreate() {
// Initialize WorkManager with the default configuration.
WorkManager.initialize(getContext(), new Configuration.Builder().build());
return true;
}
}
2.WorkManager中initialize方法调用WorkManagerImpl的initialize,并实例化WorkManagerImpl。
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
synchronized (sLock) {
if (sDelegatedInstance == null) {
context = context.getApplicationContext();
if (sDefaultInstance == null) {
sDefaultInstance = new WorkManagerImpl(
context,
configuration,
new WorkManagerTaskExecutor(configuration.getTaskExecutor()));
}
sDelegatedInstance = sDefaultInstance;
}
}
}
3.WorkManagerImpl构造方法中会创建Room数据库与任务执行器Schedulers
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, workTaskExecutor);
Processor processor = new Processor(
context,
configuration,
workTaskExecutor,
database,
schedulers);
internalInit(context, configuration, workTaskExecutor, database, schedulers, processor);
}
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));
}
createBestAvailableBackgroundScheduler方法中会根据SDK版本创建对应的后台执行器
@NonNull
static Scheduler createBestAvailableBackgroundScheduler(
@NonNull Context context,
@NonNull WorkManagerImpl workManager) {
Scheduler scheduler;
if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) {
scheduler = new SystemJobScheduler(context, workManager);
setComponentEnabled(context, SystemJobService.class, true);
Logger.get().debug(TAG, "Created SystemJobScheduler and enabled SystemJobService");
} else {
scheduler = tryCreateGcmBasedScheduler(context);
if (scheduler == null) {
scheduler = new SystemAlarmScheduler(context);
setComponentEnabled(context, SystemAlarmService.class, true);
Logger.get().debug(TAG, "Created SystemAlarmScheduler");
}
}
return scheduler;
}
1.以WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)为入口最终会追踪到WorkManagerImpl的enqueue方法
public Operation enqueue(
@NonNull List<? extends WorkRequest> workRequests) {
// 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 (workRequests.isEmpty()) {
throw new IllegalArgumentException(
"enqueue needs at least one WorkRequest.");
}
return new WorkContinuationImpl(this, workRequests).enqueue();
}
2.WorkContinuationImpl的enqueue方法中将EnqueueRunnable加入线程池
@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;
}
- 线程池执行EnqueueRunnable的run方法
@Override
public void run() {
try {
// 将WorkRequest.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));
}
}
Schedulers最终会循环遍历执行Scheduler
public void scheduleWorkInBackground() {
WorkManagerImpl workManager = mWorkContinuation.getWorkManagerImpl();
Schedulers.schedule(
workManager.getConfiguration(),
workManager.getWorkDatabase(),
workManager.getSchedulers());
}
以GreedyScheduler为例
public void schedule(@NonNull WorkSpec... workSpecs) {
registerExecutionListenerIfNeeded();
List<WorkSpec> constrainedWorkSpecs = new ArrayList<>();
List<String> constrainedWorkSpecIds = new ArrayList<>();
for (WorkSpec workSpec : workSpecs) {
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 {
// 执行任务
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);
}
}
}
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) {
// 在线程池中开始执行任务
mWorkTaskExecutor
.executeOnBackgroundThread(
new StartWorkRunnable(this, workSpecId, runtimeExtras));
}
线程池调用StartWorkRunnable的run方法
@Override
public void run() {
mWorkManagerImpl.getProcessor().startWork(mWorkSpecId, mRuntimeExtras);
}
执行Processor的startWork,在这个方法中执行WorkerWrapper的run方法:
@WorkerThread
@Override
public void run() {
mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
mWorkDescription = createWorkDescription(mTags);
runWorker();
}
runWorker方法中最终会执行Worker的startWork方法,这个方法即使用WorkManager中自定义的Worker。
- JMM与volatile关键字
- synchronized的实现原理
- synchronized等待与唤醒机制
- AQS的实现原理
- ReentrantLock的实现原理
- ReentrantLock等待与唤醒机制
- CAS、Unsafe类以及Automic并发包
- ThreadLocal的实现原理
- 线程池的实现原理
- Java线程中断机制
- 多线程与并发常见面试题
- Android基础知识汇总
- MVC、MVP与MVVM
- SparseArray实现原理
- ArrayMap的实现原理
- SharedPreferences
- Bitmap
- Activity的启动模式
- Fragment核心原理
- 组件化项目架构搭建
- 组件化WebView架构搭建
- 为什么 Activity.finish() 之后 10s 才 onDestroy ?
- Binder与AIDL
- Binder实现原理
- Android系统启动流程
- InputManagerService
- WindowManagerService
- Choreographer详解
- SurfaceFlinger
- ViewRootImpl
- ActivityManagerService
- APP启动流程
- PMS安装与签名校验
- Dalvik与ART
- 内存优化策略
- UI界面及卡顿优化
- App启动优化
- ANR问题
- 包体积优化
- APK打包流程
- 电池电量优化
- Android屏幕适配
- 线上性能监控1--线上监控切入点
- 线上性能监控2--Matrix实现原理
- Glide实现原理
- OkHttp实现原理
- Retrofit实现原理
- RxJava实现原理
- RxJava中的线程切换与线程池
- LeakCanary实现原理
- ButterKnife实现原理
- ARouter实现原理
- Tinker实现原理
- 2. 两数相加
- 19.删除链表的倒数第 N 个结点
- 21. 合并两个有序链表
- 24. 两两交换链表中的节点
- 61. 旋转链表
- 86. 分隔链表
- 92. 反转链表 II
- 141. 环形链表
- 160. 相交链表
- 206. 反转链表
- 206 反转链表 扩展
- 234. 回文链表
- 237. 删除链表中的节点
- 445. 两数相加 II
- 面试题 02.02. 返回倒数第 k 个节点
- 面试题 02.08. 环路检测
- 剑指 Offer 06. 从尾到头打印链表
- 剑指 Offer 18. 删除链表的节点
- 剑指 Offer 22. 链表中倒数第k个节点
- 剑指 Offer 35. 复杂链表的复制
- 1. 两数之和
- 11. 盛最多水的容器
- 53. 最大子序和
- 75. 颜色分类
- 124.验证回文串
- 167. 两数之和 II - 输入有序数组 -169. 多数元素
- 189.旋转数组
- 209. 长度最小的子数组
- 283.移动0
- 303.区域和检索 - 数组不可变
- 338. 比特位计数
- 448. 找到所有数组中消失的数字
- 643.有序数组的平方
- 977. 有序数组的平方