setExpedited 如何工作,它是否与前台服务一样好和可靠?

如何解决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 使用直接工作。

关于它的另一个线索是 (here) :

从 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

问题

  1. setExpedited 究竟是如何工作的?
  2. 这个“加急工作配额”是什么?当 Android 12 达到这种情况时会发生什么?工人不会立即完成工作吗?
  3. setExpedited 是否与前台服务一样可靠?它总是能够立即启动吗?
  4. setExpedited 有哪些优点、缺点和限制?为什么我更喜欢它而不是前台服务?
  5. 这是否意味着当应用在 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?