为什么首次调度的WorkManager监听拍照事件时会触发Worker执行两次?
首次触发两次日志的原因
- 核心诱因是相机写入照片到MediaStore时会触发两次内容变更事件:第一次是创建空照片文件的通知,第二次是写入完整图像数据后的变更通知。
- 你当前的实现逻辑放大了这个问题:首次调度的
OneTimeWorkRequest接收到第一次变更事件后立即执行doWork,在doWork中第一时间重新调度了新的同唯一名称的WorkRequest,此时第二次MediaStore变更事件刚好到达,而你用的ExistingWorkPolicy.REPLACE只会替换处于待执行状态的任务,已经处于运行状态的旧任务不会被终止,新调度的任务也正常存活,两个任务分别对应两次变更事件,就会输出两次日志。 - 后续运行时,新的WorkRequest调度完成后不会刚好赶上重叠的变更事件,所以只会触发一次执行。
修复方案
可以通过以下任意一种方式修复:
- 每次执行Worker时先判断变更的URI是否对应真实的、写入完成的照片文件,过滤空文件/未完成写入的文件,避免无效执行
- 在重新调度WorkRequest前加500ms左右的短延迟,避开同一次拍照产生的两次连续变更事件
- 不要在
doWork开头就重新调度任务,等本次任务的所有逻辑执行完成、确认是有效变更后再调度下一次任务
缩短新照片感知耗时的方案
WorkManager的ContentUriTrigger本身是面向低功耗后台场景设计的,系统会批量合并变更事件减少唤醒,默认有几秒到十几秒的延迟是预期行为,要缩短延迟可以:
- 当应用处于前台时,直接用
ContentResolver.registerContentObserver()实时监听MediaStore变更,这个方式可以做到毫秒级感知 - 仅当应用退到后台时再切换为WorkManager的ContentUriTrigger监听,兼顾实时性和后台存活率
内容的提问来源于stack exchange,提问作者iegrm
相关产品推荐
相关产品推荐

