ListenableWorker不会删除通知图标



我正在使用ListenableWorker执行后台任务。我还想让操作系统意识到我的服务重要性,所以我打电话给

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

正如谷歌文档中所建议的。

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

此外,我在这个通知中添加了取消按钮,但它什么都不做,我无法关闭它:

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

有什么建议吗?

我向谷歌跟踪器提交了一个问题。然后发现这完全令人担忧。

官方回应如下:

查看您的示例应用程序,您正在引入您的ListableFuture已完成,由返回回调到FutureAdaptor,以及主循环器。

即使不使用REPLACE,您的通知更新之一也是在您的Worker标记为成功后发布。

然而,您实际上可以通过等待要完成对setForegroundAsync((的调用(因为返回ListableFuture(。一旦你做到了,你就永远不会有Worker完成后显示的通知。

我还将继续提出改进意见即使开发人员弄错了,也会自动执行此操作。

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);
}

如果您有某个分支可以立即终止工作进程,请添加1秒延迟以传播通知。setForeground声称是同步的,但显然不是——总是需要显示时间通知。在未显示通知时调用cancel不会有任何作用。这显然是一种种族状况,谷歌无法处理(我甚至不确定应用程序是否能处理(。

扩展解释:

我有一个代码,在单个场景中可以立即返回。工人看起来是这样的:

setForeground(getForegroundInfo())
loggingRepository.uploadLogs()

就是这样,再简单不过了。但是,日志存储库在启动时有以下检查:

if (!userIdentity.isLoggedIn) return

所以,如果用户没有登录,什么也不做。如果这种情况发生了,通知就会一直存在。我唯一要做的就是添加这样的延迟(这是一个CoroutineWorker(

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

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

公文如下:

ListenableWorker现在支持setForegroundAsync((API,并且CoroutineWorker支持挂起setForeground((APi

因此,上述问题的解决方案是,必须在返回Result.success((之前执行繁忙作业。否则,此异常将被抛出

对setForegroundAsync((的调用必须在ListenableWorker之前完成通过返回Result的实例来表示工作完成。

检查我的代码片段以获得您的解决方案:

public static void startCloudWorker() {
OneTimeWorkRequest oneTimeWorkRequest =
new OneTimeWorkRequest.Builder(CloudWorker.class)
.setInitialDelay(..., TimeUnit.MILLISECONDS)
...
.build();
WorkManager workManager = getWorkManager();
workManager.enqueue(oneTimeWorkRequest);
}

public class CloudWorker extends Worker {
public CloudWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
final ForegroundInfo foregroundInfo = createForegroundInfo(...)
setForegroundAsync(foregroundInfo);

// Some busy job here...
return Result.success();
}
}

最好忘记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);

最新更新