两个或多个带有进度的前台通知在更新其进度时相互替换
Two or more Foreground Notification with Progress is replacing each other while updating its progress
我有一项服务会 运行 在前台上传任务,然后在通知中显示进度。由于用户可能会使用不同的 ID 请求多次上传,因此会有两个或多个前台服务 运行。一切正常,但我想要的是使用此代码显示所有任务的进度通知。
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false);
NotificationManager manager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(code, builder.build());
startForeground(code,builder.build());
但不幸的是,通知只是被覆盖了,但如果我删除了 startForeground() 那么一切正常,因为它根据正在进行的任务显示多个进度通知,但如果内存不足,系统可能会终止进程这就是为什么我希望它在前景中 运行。那么我如何才能在前台显示与正在进行的任务数量相等的通知数量?
不同的通知使用不同的id。在此代码中,您使用相同的默认 ID,因此新通知将替换旧通知。
您应该传递不同的 Id 以获得不同的通知。
在您的代码中:
使用getId()
方法为每个通知获取不同的ID:
private static final AtomicInteger c = new AtomicInteger(0);
public static int getID() {
return c.incrementAndGet();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false);
NotificationManager manager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(getId(), builder.build());
startForeground(getId(),builder.build()); // you need to pass different id here. Or i think this method is not there.
对于androidO您需要通知渠道:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setSound(notification, Notification.AUDIO_ATTRIBUTES_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSound(notification)
.setContentIntent(pendingIntent)
.setContentText(message)
.setContentTitle(getResources().getString(R.string.app_name))
.setSmallIcon(R.drawable.ic_visualogyx_notification)
.setStyle(new NotificationCompat.BigTextStyle().bigText(message).setBigContentTitle(getResources().getString(R.string.app_name)))
.setTicker("Hearty365")
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_round));
notificationManager.notify(getID(),notificationBuilder.build());
我终于知道怎么做了。
首先,我需要 运行 它在 onCreate 中有一点延迟。
@Override
public void onCreate (){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startForeground(requestCode, getMyActivityNotification("",completedParts,totalSize));
}
},500);
}
然后创建通知提供程序方法。
//Notification provider
private Notification getMyActivityNotification(String caption, long completedUnits, long totalUnits){
int percentComplete = 0;
if (totalUnits > 0) {
percentComplete = (int) (100 * completedUnits / totalUnits);
}
//Return the latest progress of task
return new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false)
.build();
}
那么更新通知进度应该和调用前台分开
/**
* Show notification with a progress bar.
* Updating the progress happens here
*/
protected void showProgressNotification(String caption, long completedUnits, long totalUnits, int code) {
createDefaultChannel();
mCaption = caption;
requestCode = code;
completedParts = completedUnits;
totalSize = totalUnits;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
//Update the notification bar progress
mNotificationManager.notify(requestCode, getMyActivityNotification(caption,completedUnits,totalUnits));
}
}
在调用 startForeground 之前,您需要调用 ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)
以保留旧通知。
以下是一个实用程序class,您可以在前台服务中使用它来管理通知:
class ForegroundNotifications(
private val context: Context,
private val foregroundServiceHelper: ForegroundServiceHelper,
private val notificationService: NotificationService
) {
var activeNotificationId: Int? = null
private set
val notificationIds: Set<Int>
get() = entries.keys
val isEmpty: Boolean
get() = entries.isEmpty()
private val entries: LinkedHashMap<Int, Notification> = LinkedHashMap()
fun notifyAndDetachPrevious(notificationId: Int, notification: Notification) {
synchronized(this) {
foregroundServiceHelper.startForegroundAndDetachPreviousNotification(
notificationId,
notification
)
entries[notificationId] = notification
activeNotificationId = notificationId
}
}
fun cancel(notificationId: Int) {
synchronized(this) {
if (notificationId == activeNotificationId) {
val newActiveNotificationId = entries.keys.findLast { it != activeNotificationId }
val notification = entries[newActiveNotificationId]
if (newActiveNotificationId != null && notification != null) {
notifyAndDetachPrevious(newActiveNotificationId, notification)
}
}
entries.remove(notificationId)
if (isEmpty) {
foregroundServiceHelper.stopForeground()
} else {
notificationService.cancel(context, id = notificationId)
}
}
}
}
interface NotificationService {
fun createDefaultChannel(context: Context)
fun notify(context: Context, tag: String? = null, id: Int, notification: Notification)
fun cancel(context: Context, tag: String? = null, id: Int)
}
interface ForegroundServiceHelper {
fun startForegroundAndDetachPreviousNotification(
notificationId: Int,
notification: Notification
)
fun stopForeground()
}
class ForegroundServiceHelperImpl(
private val service: Service
) : ForegroundServiceHelper {
override fun startForegroundAndDetachPreviousNotification(
notificationId: Int,
notification: Notification
) {
ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)
service.startForeground(notificationId, notification)
}
override fun stopForeground() {
ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_REMOVE)
}
}
我有一项服务会 运行 在前台上传任务,然后在通知中显示进度。由于用户可能会使用不同的 ID 请求多次上传,因此会有两个或多个前台服务 运行。一切正常,但我想要的是使用此代码显示所有任务的进度通知。
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false);
NotificationManager manager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(code, builder.build());
startForeground(code,builder.build());
但不幸的是,通知只是被覆盖了,但如果我删除了 startForeground() 那么一切正常,因为它根据正在进行的任务显示多个进度通知,但如果内存不足,系统可能会终止进程这就是为什么我希望它在前景中 运行。那么我如何才能在前台显示与正在进行的任务数量相等的通知数量?
不同的通知使用不同的id。在此代码中,您使用相同的默认 ID,因此新通知将替换旧通知。
您应该传递不同的 Id 以获得不同的通知。
在您的代码中:
使用getId()
方法为每个通知获取不同的ID:
private static final AtomicInteger c = new AtomicInteger(0);
public static int getID() {
return c.incrementAndGet();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false);
NotificationManager manager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(getId(), builder.build());
startForeground(getId(),builder.build()); // you need to pass different id here. Or i think this method is not there.
对于androidO您需要通知渠道:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setSound(notification, Notification.AUDIO_ATTRIBUTES_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSound(notification)
.setContentIntent(pendingIntent)
.setContentText(message)
.setContentTitle(getResources().getString(R.string.app_name))
.setSmallIcon(R.drawable.ic_visualogyx_notification)
.setStyle(new NotificationCompat.BigTextStyle().bigText(message).setBigContentTitle(getResources().getString(R.string.app_name)))
.setTicker("Hearty365")
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher_round));
notificationManager.notify(getID(),notificationBuilder.build());
我终于知道怎么做了。 首先,我需要 运行 它在 onCreate 中有一点延迟。
@Override
public void onCreate (){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startForeground(requestCode, getMyActivityNotification("",completedParts,totalSize));
}
},500);
}
然后创建通知提供程序方法。
//Notification provider
private Notification getMyActivityNotification(String caption, long completedUnits, long totalUnits){
int percentComplete = 0;
if (totalUnits > 0) {
percentComplete = (int) (100 * completedUnits / totalUnits);
}
//Return the latest progress of task
return new NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_file_upload_white_24dp)
.setContentTitle(getString(R.string.app_name))
.setContentText(caption)
.setProgress(100, percentComplete, false)
.setContentInfo(String.valueOf(percentComplete +"%"))
.setOngoing(true)
.setAutoCancel(false)
.build();
}
那么更新通知进度应该和调用前台分开
/**
* Show notification with a progress bar.
* Updating the progress happens here
*/
protected void showProgressNotification(String caption, long completedUnits, long totalUnits, int code) {
createDefaultChannel();
mCaption = caption;
requestCode = code;
completedParts = completedUnits;
totalSize = totalUnits;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
//Update the notification bar progress
mNotificationManager.notify(requestCode, getMyActivityNotification(caption,completedUnits,totalUnits));
}
}
在调用 startForeground 之前,您需要调用 ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)
以保留旧通知。
以下是一个实用程序class,您可以在前台服务中使用它来管理通知:
class ForegroundNotifications(
private val context: Context,
private val foregroundServiceHelper: ForegroundServiceHelper,
private val notificationService: NotificationService
) {
var activeNotificationId: Int? = null
private set
val notificationIds: Set<Int>
get() = entries.keys
val isEmpty: Boolean
get() = entries.isEmpty()
private val entries: LinkedHashMap<Int, Notification> = LinkedHashMap()
fun notifyAndDetachPrevious(notificationId: Int, notification: Notification) {
synchronized(this) {
foregroundServiceHelper.startForegroundAndDetachPreviousNotification(
notificationId,
notification
)
entries[notificationId] = notification
activeNotificationId = notificationId
}
}
fun cancel(notificationId: Int) {
synchronized(this) {
if (notificationId == activeNotificationId) {
val newActiveNotificationId = entries.keys.findLast { it != activeNotificationId }
val notification = entries[newActiveNotificationId]
if (newActiveNotificationId != null && notification != null) {
notifyAndDetachPrevious(newActiveNotificationId, notification)
}
}
entries.remove(notificationId)
if (isEmpty) {
foregroundServiceHelper.stopForeground()
} else {
notificationService.cancel(context, id = notificationId)
}
}
}
}
interface NotificationService {
fun createDefaultChannel(context: Context)
fun notify(context: Context, tag: String? = null, id: Int, notification: Notification)
fun cancel(context: Context, tag: String? = null, id: Int)
}
interface ForegroundServiceHelper {
fun startForegroundAndDetachPreviousNotification(
notificationId: Int,
notification: Notification
)
fun stopForeground()
}
class ForegroundServiceHelperImpl(
private val service: Service
) : ForegroundServiceHelper {
override fun startForegroundAndDetachPreviousNotification(
notificationId: Int,
notification: Notification
) {
ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)
service.startForeground(notificationId, notification)
}
override fun stopForeground() {
ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_REMOVE)
}
}