升级到 WorkManager 2.7.0:如何为 RxWorker 实现 getForegroundInfoAsync?

Upgrading to WorkManager 2.7.0: How to implement getForegroundInfoAsync for RxWorker?

我的应用程序的目标是 API 31/Android 12,根据 Google, so in order to do that, I have added setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) to my OneTimeWorkRequestBuilder and added the necessary changes in the AndroidManifest as well (see this link 了解详情,需要 WorkManager 2.7.0 版)。但是,当我 运行 我的应用程序遇到此错误时:

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()`

Google 没有提供关于如何为 RxWorker 执行此操作的示例或文档,但我在 Whosebug 中找到了这个 ,但它适用于协程。

我的问题是,当 getForegroundInfoAsync 必须 return ListenableFuture<ForegroundInfo> 时,您如何为 RxWorker 实现上述 getForegroundInfoAsync——阅读文档似乎我必须将 Guava 添加到我的应用程序才能执行此操作吗?由于 ListenableFuture 的文档对 Avoid implementing ListenableFuture from scratch. If you can't get by with the standard implementations, prefer to derive a new Future instance with the methods in Futures or, if necessary, to extend AbstractFuture.

编辑:目前,有两种方法可以解决这个问题:

1.使用限制 API

查看 ListenableWorker 的源代码,我们发现 getForegroundInfoAsync:

    @NonNull
    public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
        SettableFuture<ForegroundInfo> future = SettableFuture.create();
        String message =
                "Expedited WorkRequests require a ListenableWorker to provide an implementation for"
                        + " `getForegroundInfoAsync()`";
        future.setException(new IllegalStateException(message));
        return future;
    }

所以在我自己的 RxWorker 的 getForegroundInfoAsync 实现中,我尝试创建一个 SettableFuture 但我看到一个 lint 警告告诉我 SettableFuture 的使用在它的库中受到限制。但这可以通过将实现 getForegroundInfoAsync 注释为 @SuppressLint("RestrictedApi") 来绕过。这是我的代码大致的样子:

    @SuppressLint("RestrictedApi")
    override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
        val future = SettableFuture.create<ForegroundInfo>()

        val notificationId = id.hashCode()
        val fileName = inputData.getString(KEY_OUTPUT_FILE_NAME)

        if (fileName == null) {
            future.setException(IllegalStateException("Filename is null"))
            return future
        }

        val notificationBuilder = getNotificationBuilder(fileName)

        future.set(ForegroundInfo(notificationId, notificationBuilder.build()))
        return future
    }

2。使用 CallbackToFutureAdapter

您可以使用 CallbackToFutureAdapter 而不是依赖受限制的 API,但此解决方案需要 Futures AndroidX 库,请参阅 link here。将上述库添加到您的项目后,您可以使用 CallbackToFutureAdapter 到 return 一个 ListenableFuture 这样的方式:

override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
    val fileName = inputData.getString(KEY_OUTPUT_FILE_NAME)

    return CallbackToFutureAdapter.getFuture {
        if (fileName == null) {
            it.setException(IllegalStateException("Filename is null"))
        } else {
            notificationBuilder = getNotificationBuilder(fileName)

            it.set(ForegroundInfo(notificationId, notificationBuilder.build()))
        }
    }
}

但有一个警告,在为您的通知创建 PendingIntent 时,不要忘记设置 PendingIntent.FLAG_MUTABLE 标志(有关详细信息,请参阅此

另一种不需要限制 API 或导入期货库的方法是使用 Futures.immediateFuture() 方法:

override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> {
    val notificationId = // some int id for your notification
    val notification = // build your notification in the normal way
    return Futures.immediateFuture(ForegroundInfo(notificationId, notification))
}