首页 > 解决方案 > 加急工作请求需要 ListenableWorker 来提供 getForegroundInfoAsync() 的实现

问题描述

在这里做一些危险的问答

我有一些工作有时需要按照2.7.0 版中的描述快速运行:WorkManager

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED).build()
val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MyWorker::class.java)
    .setInitialDelay(2, TimeUnit.SECONDS)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .setConstraints(constraints).build()
WorkManager.getInstance(context).enqueueUniqueWork("my-identifier", ExistingWorkPolicy.REPLACE, oneTimeWorkRequest)

我相信代码在 Android 12/S 上运行得很好,但是当作业在 Android 11 上运行时,我收到以下错误:

E/WM-WorkerWrapper: Work [ id=<UUID>, tags={ [WorkerTag] } ] failed because it threw an exception/error
     java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: java.lang.IllegalStateException: Expedited WorkRequests require a ListenableWorker to provide an implementation for `getForegroundInfoAsync()`
        at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
        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)

我需要做什么?

标签: androidandroid-jetpackandroid-workmanager

解决方案


的文档ListenableWorker.getForegroundInfoAsync()说明了这一点:

在 Android S 之前,WorkManager 代表您管理和运行前台服务来执行 WorkRequest,显示 ForegroundInfo 中提供的通知。要随后更新此通知,应用程序可以使用 NotificationManager。

从 Android S 及更高版本开始,WorkManager 使用即时作业管理此 WorkRequest。

因此,在扩展类中,ListenableWorker有必要覆盖getForegroundInfoAsync().

自己直接覆盖该方法的另一种方法是使用例如CoroutineWorker

    class MyWorker(val context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {

    companion object {
        private const val NOTIFICATION_CHANNEL_ID = "11"
        private const val NOTIFICATION_CHANNEL_NAME = "Work Service"
    }

    override suspend fun doWork(): Result {
        // TODO: Do work here
        return Result.success()
    }

    override suspend fun getForegroundInfo(): ForegroundInfo {
        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                NOTIFICATION_CHANNEL_ID,
                NOTIFICATION_CHANNEL_NAME,
                NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
            .setContentIntent(PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), Constants.PENDING_INTENT_FLAG_IMMUTABLE))
            .setSmallIcon(R.drawable.ic_refresh_24dp)
            .setOngoing(true)
            .setAutoCancel(true)
            .setOnlyAlertOnce(true)
            .setPriority(NotificationCompat.PRIORITY_MIN)
            .setContentTitle(context.getString(R.string.app_name))
            .setLocalOnly(true)
            .setVisibility(NotificationCompat.VISIBILITY_SECRET)
            .setContentText("Updating widget")
            .build()
        return ForegroundInfo(1337, notification)
    }

}

(待定意图标志的常量实际上只是val PENDING_INTENT_FLAG_MUTABLE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_MUTABLE else 0为了使东西同时适用于 Android 12/S 及更早版本。)


推荐阅读