AlarmManager触发后WorkManager的doWork()方法未被调用
通过AlarmManager按设定频率触发广播,广播接收器WorkAlarmReceiver的onReceive方法可正常进入,但调用WorkManager入队的OneTimeWorkRequest始终不执行doWork()方法,故障为突发出现,此前代码运行正常。
涉及的核心代码如下:
广播接收器代码:
public class WorkAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { final String TAG = "WorkAlarmReceiver"; if (BuildConfig.DEBUG) { Log.i(TAG, "onReceive: intent=" + intent); } OneTimeWorkRequest startWork = new OneTimeWorkRequest.Builder(WorkManagerForTools.class).build(); WorkManager.getInstance(context).enqueueUniqueWork("Validate Tool", ExistingWorkPolicy.APPEND_OR_REPLACE , startWork); }
AlarmManager配置代码:
//checking if alarm is working with pendingIntent Intent workIntent = new Intent(mContext, WorkAlarmReceiver.class) .setAction(Long.toString(System.currentTimeMillis() PendingIntent workPendingIntent = PendingIntent.getBroadcast(mContext, 1001, workIntent, PendingIntent.FLAG_UPDATE_CURRENT); Log.e(TAG, "New data of pending intent: " + workSpecId + " local work id, " + localWorkId + " tools id list " + updatedMobileAppToolIds); if(BuildConfig.DEBUG) { Log.d(TAG, "New data of pending intent: " + workSpecId + " local work id, " + localWorkId + " tools id list " + updatedMobileAppToolIds); } boolean isWorking = (PendingIntent.getBroadcast(mContext, 1001, workIntent, PendingIntent.FLAG_NO_CREATE) != null);//just changed the flag if (isWorking) { alarmManager.cancel(workPendingIntent); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10 * (minFrequency / 10), workPendingIntent); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10 * (minFrequency / 10), workPendingIntent); }
Worker类代码:
@SuppressLint("WrongThread") @NonNull @Override public Result doWork() { // Code to be execute }
按优先级从高到低排查:
先查WorkManager运行日志与入队状态
不要仅以onReceive执行作为入队成功的判断依据,在enqueueUniqueWork调用后打印当前WorkRequest的ID,同时过滤logcat中WM-前缀的系统日志,重点看是否有实例化Worker失败、入队被拒、任务被限流的报错。
最常见的突发故障原因是升级版本后开启了代码混淆,Worker类被混淆改名,WorkManager通过反射找不到对应类,直接入队失败。解决方法是在混淆规则中添加Worker相关的keep配置:-keep class * extends androidx.work.Worker -keep class * extends androidx.work.ListenableWorker { public <init>(android.content.Context, androidx.work.WorkerParameters); }同时确认
WorkManagerForTools类存在public 类名(Context context, WorkerParameters params)的公开构造方法,没有被新增的其他构造方法覆盖,否则反射创建实例失败也不会进入doWork。检查唯一工作队列的残留任务
你使用的ExistingWorkPolicy.APPEND_OR_REPLACE策略逻辑为:如果当前同名("Validate Tool")的工作链中存在未进入终态(SUCCEEDED/FAILED/CANCELLED)的任务,新入队的任务会追加到队列尾部,等待前序任务执行完成后再运行。如果之前某次入队的Work因为异常、进程被杀等原因卡在ENQUEUED/RUNNING状态,后续所有新入队的任务都会被阻塞,永远不会触发执行。
排查方法:入队前调用WorkManager.getInstance(context).getWorkInfosForUniqueWork("Validate Tool").get(),打印该唯一工作名下所有任务的状态,确认是否有残留的卡住任务。
解决方法:如果业务不需要任务排队执行,直接将工作策略替换为ExistingWorkPolicy.REPLACE,新任务入队时自动取消旧的阻塞任务;如果需要保留排队逻辑,给任务配置合理的超时时间,避免任务永久卡住。检查AlarmManager配置的合法性
首先修正代码中明显的语法问题:setAction(Long.toString(System.currentTimeMillis()缺少右括号,虽然你反馈onReceive可以正常进入,但要确认实际运行代码不存在这类语法错误。
其次检查重复间隔的计算逻辑:10 * (minFrequency / 10)是整数除法,如果minFrequency小于10,计算结果为0,会导致AlarmManager短时间内高频触发,瞬间入队大量Work,触发WorkManager的限流机制拦截任务。同时注意Android 4.4以上setRepeating的最小允许间隔为1分钟,小于该值的间隔会被系统自动调整为1分钟。
另外如果targetSdkVersion升级到31及以上,配置PendingIntent必须添加FLAG_IMMUTABLE或FLAG_MUTABLE标志,仅用FLAG_UPDATE_CURRENT会导致PendingIntent行为异常。检查系统后台限制影响
如果应用在前台时手动触发广播可以正常执行Work,切到后台后就无法触发,基本是厂商ROM省电策略、Android版本后台启动限制拦截了任务。这种场景下可以将Work配置为加急作业,提升任务优先级,绕过部分后台限制:OneTimeWorkRequest startWork = new OneTimeWorkRequest.Builder(WorkManagerForTools.class) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build();另外获取WorkManager实例时建议传入Application级别的context,避免使用广播接收器的context导致实例初始化异常:
WorkManager.getInstance(context.getApplicationContext())。
内容的提问来源于stack exchange,提问作者Ali Chandorewala

