ListenableWorker 不移除通知图标

ListenableWorker does not remove notification icon

我正在使用 ListenableWorker 执行后台任务。 我也想让 OS 知道我的服务重要性,所以我打电话给

 setForegroundAsync(new ForegroundInfo(WorkerConstants.NOTIFICATION_FOREGROUND_ID,
 builder.build()));

如 google 文档中所建议。

但是当我的服务停止或取消时,我仍然可以看到前台服务通知,但我无法删除它。

此外,我在此通知中添加了取消按钮,但它没有任何作用,我无法关闭它:

PendingIntent intent = WorkManager.getInstance(getApplicationContext())
                            .createCancelPendingIntent(getId());
                    builder.addAction(R.drawable.ic_redesign_exit,"Stop",intent);

有什么建议吗?

最好忘记 setForegroundAsync 并按照此处说明的传统方式进行操作: https://developer.android.com/training/notify-user/build-notification

这是我使用的:

    Context context = getApplicationContext();
    String title = context.getString(R.string.str_synchronisation);
    String cancel = context.getString(R.string.str_cancel_synchronisation);
    // This PendingIntent can be used to cancel the worker
    PendingIntent intent = WorkManager.getInstance(context)
            .createCancelPendingIntent(getId());
    //notificationManager.cancel(notification_ID);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, notif_ch_id)
            .setSmallIcon(R.drawable.ic_sync_black_24dp)
            .setContentTitle(title)
            .setContentText("Use this Content")
            .setOngoing(true)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
//                // Add the cancel action to the notification which can
//                // be used to cancel the worker
            .addAction(android.R.drawable.ic_delete, cancel, intent);
    notificationManager.notify(notification_ID, builder.build());

不要忘记保留通知管理器的实例:

notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);

更新您的通知:

builder.setContentText(context.getString(R.string.str_veuiller_patienter)
                + ", fichier " + String.valueOf(i + 1) + totalfiles);
notificationManager.notify(notification_ID, builder.build());

取消您的通知:

notificationManager.cancel(notification_ID);

我用这个向 google 跟踪器提交了一个问题。并发现那完全是破旧的。

官方回复如下:

Looking at your sample app, you are introducing a race between completion of your ListenableFuture returned by CallbackToFutureAdaptor, and the main looper.

Even without the use of REPLACE one of your Notification updates is posted after your Worker is marked as successful.

However, you can actually avoid the race condition by waiting for the call to setForegroundAsync() to be completed (because that also returns a ListenableFuture). Once you do that - you never have a notification that shows up after your Worker is done.

I will also go ahead and file an improvement on how we can automatically do this even when developers get this wrong.

try {
    // This ensures that you waiting for the Notification update to be done.
    setForegroundAsync(createForegroundInfo(0)).get();
} catch (Throwable throwable) {
    // Handle this exception gracefully
    Log.e("FgLW", "Something bad happened", throwable);
}

最新版本的 Work Manager 库中有一个名为 setForeground() 的 ktx 挂起函数,如果您使用协程,它会对侦听器执行 .await() 并将其变为同步。

如果您有一些可以立即结束工作人员的分支 - 添加 1 秒延迟通知传播。 setForeground 声称是同步的,但显然不是 - 总是需要显示时间通知。并且在未显示的通知上调用取消不会执行任何操作。这显然是一种竞争条件,google 无法处理(我什至不确定应用程序是否可以处理)。

扩展说明:

我有代码可以在单个场景中立即 return。工人看起来像这样:

setForeground(getForegroundInfo())
loggingRepository.uploadLogs()

就是这样,再简单不过了。但是,日志存储库在开始时有这个检查:

if (!userIdentity.isLoggedIn) return

因此,如果用户未登录 - 什么也不做。如果这种情况发生了 - 通知就会一直存在。我唯一要做的就是像那样添加延迟(这是一个 CoroutineWorker)

setForeground(getForegroundInfo())
loggingRepository.uploadLogs()
delay(1000)