两个或多个带有进度的前景通知在更新进度时互相替换

时间:2018-07-09 10:34:51

标签: android android-notifications

我有一项服务,该服务将在前台运行上传任务,然后在通知中显示进度。由于用户可能使用不同的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(),那么一切都会正常进行,因为它根据正在进行的任务数量显示了多个进度通知,但是如果内存不足,系统可能会终止该进程,这就是为什么我希望它在前台运行。那么,如何显示与前台中正在进行的任务数量相等的通知数量?

4 个答案:

答案 0 :(得分:1)

在致电startForeground之前,您需要致电ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH)来保留旧的通知。

下面是一个实用程序类,您可以在前台服务中使用它来管理通知:

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

}

答案 1 :(得分:0)

对不同的通知使用不同的ID。在此代码中,您使用相同的默认ID,因此新通知将替换旧通知。

答案 2 :(得分:0)

您应该传递不同的 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.

对于Android O ,您需要通知频道:

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

答案 3 :(得分:0)

最后我弄清楚了怎么做。 首先,我需要稍稍延迟地在onCreate内运行它。

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

然后将更新通知进度与调用前台分开。

{{1}}