WorkManager周期性CoroutineWorker触发JobCancellationException问题求助
WorkManager周期性任务执行10分钟后被取消问题排查
问题描述
创建了一个简单的CoroutineWorker,循环执行1000次,每次延迟1000毫秒。该Worker是唯一周期性任务,重复间隔为15分钟,ExistingPeriodicWorkPolicy设置为KEEP。但启动Worker后,执行约10分钟时任务被取消,抛出JobCancellationException异常。
完整异常信息
Exception kotlinx.coroutines.JobCancellationException: Job was cancelled; job=JobImpl{Cancelling}@ba57765 12:55:47.088 WM-Wor...rapper I Work [ id=4c44c3da-3c57-4cac-a40a-82c948125807, tags={ com.sk.workmanagerdemo1.DownloadingWorker } ] was cancelled java.util.concurrent.CancellationException: Task was cancelled. at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184) at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514) at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475) at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:311) at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923)
Worker代码
import android.content.Context import android.util.Log import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import java.text.SimpleDateFormat import java.util.* class DownloadingWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { return withContext(Dispatchers.IO) { Log.i("MYTAG", "Started ${getCurrentDateTime()}") return@withContext try { for (i in 0..1000) { delay(1000) Log.i("MYTAG", "Downloading $i") } Log.i("MYTAG", "Completed ${getCurrentDateTime()}") Result.success() } catch (e: Exception) { Log.i("MYTAG", "Exception $e") Result.failure() } } } private fun getCurrentDateTime(): String { val time = SimpleDateFormat("dd/M/yyyy hh:mm:ss") return time.format(Date()) } }
任务启动代码
private fun setPeriodicWorkRequest() { val downloadConstraints = Constraints.Builder() .setRequiresCharging(true) .setRequiredNetworkType(NetworkType.CONNECTED) .build() val periodicWorkRequest = PeriodicWorkRequest .Builder(DownloadingWorker::class.java, 15, TimeUnit.MINUTES) .setConstraints(downloadConstraints) .build() WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork( "DownloadWorker", ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest ) }
原因分析
- WorkManager单次任务超时限制:WorkManager对单次Worker任务的执行时长有默认限制,多数设备约为10分钟。你的Worker单次执行需要1000秒(约16.7分钟),远超限制,系统会自动取消超时任务。
- 约束条件变化(次要可能):如果执行过程中设备停止充电或网络断开,WorkManager会取消当前任务,但从异常时间点看,超时是主要原因。
解决方案
方案1:拆分长任务为多批次执行
把单次1000次循环拆分成每次执行一部分,通过输入输出参数记录进度,依赖下一次周期性触发继续执行:
override suspend fun doWork(): Result { return withContext(Dispatchers.IO) { val currentProgress = inputData.getInt("PROGRESS", 0) Log.i("MYTAG", "Started from $currentProgress at ${getCurrentDateTime()}") return@withContext try { val end = min(currentProgress + 100, 1000) for (i in currentProgress until end) { delay(1000) Log.i("MYTAG", "Downloading $i") } if (end >= 1000) { Log.i("MYTAG", "Completed ${getCurrentDateTime()}") Result.success() } else { val outputData = workDataOf("PROGRESS" to end) Log.i("MYTAG", "Progress updated to $end, waiting next cycle") Result.success(outputData) } } catch (e: Exception) { Log.i("MYTAG", "Exception $e") Result.failure() } } }
启动任务时初始化进度:
val periodicWorkRequest = PeriodicWorkRequest .Builder(DownloadingWorker::class.java, 15, TimeUnit.MINUTES) .setConstraints(downloadConstraints) .setInputData(workDataOf("PROGRESS" to 0)) .build()
方案2:使用前台服务避免超时(不推荐用于循环任务)
如果必须单次完成,可将Worker改为前台服务,避免系统后台超时取消,但会显示通知,影响用户体验:
override suspend fun doWork(): Result { // 创建前台通知(需提前创建通知渠道,适配Android O+) val notification = NotificationCompat.Builder(applicationContext, "DOWNLOAD_CHANNEL") .setContentTitle("Downloading") .setContentText("In progress...") .setSmallIcon(R.drawable.ic_download) .build() setForeground(ForegroundInfo(1001, notification)) // 原循环执行代码... }
方案3:调整系统配置(不推荐)
部分厂商设备允许调整后台任务超时,但兼容性差,无法保证所有设备生效,不依赖此方案。
额外建议
- 避免用WorkManager执行超过10分钟的单次任务,它的设计定位是短时间后台任务或周期性任务。
- 周期性任务间隔要匹配单次任务时长,避免任务堆积。
内容的提问来源于stack exchange,提问作者sandeep kolhal
相关产品推荐
相关产品推荐

