如何解决setExpedited 如何工作,它是否与前台服务一样好和可靠?
背景
过去,我使用前台 IntentService 来处理接踵而至的各种事件。然后它在 Android 11 到来时被弃用(Android R,API 30),据说它更喜欢使用使用 setForegroundAsync 的 Worker,所以我做到了。
val builder = NotificationCompat.Builder(context,...)...
setForegroundAsync(ForegroundInfo(notificationId,builder.build()))
问题
随着 Android 12(Android S,API 31)的到来,仅在 之后的一个版本,现在 setForegroundAsync
被标记为已弃用,我被告知使用 setExpedited 代替:
* @deprecated Use {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)} and
* {@link ListenableWorker#getForegroundInfoAsync()} instead.
问题是,我不确定它究竟是如何工作的。之前,我们有一个通知,应该在用户使用前台服务时向其显示(至少对于“旧”Android 版本而言)。现在看来 getForegroundInfoAsync 用于它,但我认为它不会用于 Android 12 :
在 Android S 之前,WorkManager 管理和运行一个前台服务 代表您执行 WorkRequest,显示通知 在 ForegroundInfo 中提供。更新此通知 随后,应用程序可以使用 notificationmanager。
从Android S及以上开始,WorkManager管理这个WorkRequest 使用直接工作。
从 WorkManager 2.7.0 开始,您的应用程序可以调用 setExpedited() 来 声明 Worker 应该使用加急作业。这个新的 API 使用 在 Android 12 上运行时加速作业,并且 API 使用前台 以前版本的 Android 上的服务以向后提供 兼容性。
他们拥有的唯一片段是调度本身:
OneTimeWorkRequestBuilder<T>().apply {
setInputData(inputData)
setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
}.build()
即使是 OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST 的文档也很奇怪:
当应用没有任何加急工作配额时,加急工作 请求将回退到常规工作请求。
我想要的只是立即、可靠地、不中断地(或至少是尽可能低的机会)做某事,并使用操作系统提供的任何东西来做。
我不明白为什么创建 setExpedited
。
问题
-
setExpedited
究竟是如何工作的? - 这个“加急工作配额”是什么?当 Android 12 达到这种情况时会发生什么?工人不会立即完成工作吗?
-
setExpedited
是否与前台服务一样可靠?它总是能够立即启动吗? -
setExpedited
有哪些优点、缺点和限制?为什么我更喜欢它而不是前台服务? - 这是否意味着当应用在 Android 12 上使用此 API 时,用户将看不到任何内容?
解决方法
ad 1. 我无法准确解释(还没有研究代码),但从我们(开发人员)的角度来看,它就像一个工作请求队列,将您的应用程序工作配额考虑在内。所以基本上你可以依靠它如果你的应用在电池方面表现得很好(不管这意味着什么......)
ad 2. 每个应用都有一些不能超过的配额。此配额的详细信息是(并且可能始终是)OEM 内部实施详细信息。至于达到配额 - 这正是 OutOfQuotaPolicy
标志的用途。您可以设置,如果您的应用达到其配额 - 作业可以作为正常作业运行,也可以删除
广告 3. 那是个谜。 Here 我们可以找到模糊的陈述:
Android 12 中新增的加速作业允许应用执行简短的重要任务,同时让系统更好地控制对资源的访问。这些作业具有介于前台服务和常规 JobScheduler 作业之间的一组特征
这(据我所知)意味着工作经理仅适用于短期运行的工作。因此,从后台启动长时间运行的作业似乎不是任何官方方式。哪个(我的意见)很疯狂,但是嘿 - 就是这样。
我们所知道的是,它应该立即启动,但可能会被推迟。 source
ad 4. 不能从后台运行前台服务。因此,如果您需要在应用程序不在前台时运行“几分钟任务” - 加急作业将是在 android 12 中执行此操作的唯一方法。想要运行更长的任务吗?你需要让你进入前台。它可能需要您运行作业来显示启动活动的通知。比从活动你可以运行前台服务!已经很兴奋了吗?
广告 5. 在 android 12 上,他们什么也看不到。在早期版本中,加急作业将回退到前台服务。您需要覆盖 public open suspend fun getForegroundInfo(): ForegroundInfo
才能进行自定义通知。我不确定如果你不覆盖它会发生什么。
示例用法(日志上传工作者):
@HiltWorker
class LogReporterWorker @AssistedInject constructor(
@Assisted appContext: Context,@Assisted workerParams: WorkerParameters,private val loggingRepository: LoggingRepository,) : CoroutineWorker(appContext,workerParams) {
override suspend fun doWork(): Result {
loggingRepository.uploadLogs()
}
override suspend fun getForegroundInfo(): ForegroundInfo {
SystemNotificationsHandler.registerForegroundServiceChannel(applicationContext)
val notification = NotificationCompat.Builder(
applicationContext,SystemNotificationsHandler.FOREGROUND_SERVICE_CHANNEL
)
.setContentTitle(Res.string(R.string.uploading_logs))
.setSmallIcon(R.drawable.ic_logo_small)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(
NOTIFICATION_ID,notification,ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
ForegroundInfo(
NOTIFICATION_ID,notification
)
}
}
companion object {
private const val TAG = "LogReporterWorker"
private const val INTERVAL_HOURS = 1L
private const val NOTIFICATION_ID = 3562
fun schedule(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
val worker = PeriodicWorkRequestBuilder<LogReporterWorker>(
INTERVAL_HOURS,TimeUnit.HOURS
)
.setConstraints(constraints)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.addTag(TAG)
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(TAG,ExistingPeriodicWorkPolicy.REPLACE,worker)
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。