Expedited WorkRequests 需要 ListenableWorker 来提供 getForegroundInfoAsync() 的实现
Expedited WorkRequests require a ListenableWorker to provide an implementation for getForegroundInfoAsync()
在这里做一点Jeopardy style Q&A。
我有一些工作,有时需要 运行 作为 加急,如 version 2.7.0 of 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.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)
我需要做什么?
The documentation for ListenableWorker.getForegroundInfoAsync()
指出:
Prior to Android S, WorkManager manages and runs a foreground service on your behalf to execute the WorkRequest, showing the notification provided in the ForegroundInfo. To update this notification subsequently, the application can use NotificationManager.
Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
所以在 class 扩展 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 和更早版本一起工作。)
在这里做一点Jeopardy style Q&A。
我有一些工作,有时需要 运行 作为 加急,如 version 2.7.0 of 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.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)
我需要做什么?
The documentation for ListenableWorker.getForegroundInfoAsync()
指出:
Prior to Android S, WorkManager manages and runs a foreground service on your behalf to execute the WorkRequest, showing the notification provided in the ForegroundInfo. To update this notification subsequently, the application can use NotificationManager.
Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
所以在 class 扩展 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 和更早版本一起工作。)