I have a service that will run a upload task in foreground then showing a progress in the notification. Since a user may upload multiple times with different id request then the
Before you call startForeground, you need to call ServiceCompat.stopForeground(service, ServiceCompat.STOP_FOREGROUND_DETACH) to keep the old notification(s).
The following is a utility class that you can use in the foreground service to manage the notifications:
class ForegroundNotifications(
private val context: Context,
private val foregroundServiceHelper: ForegroundServiceHelper,
private val notificationService: NotificationService
) {
var activeNotificationId: Int? = null
private set
val notificationIds: Set
get() = entries.keys
val isEmpty: Boolean
get() = entries.isEmpty()
private val entries: LinkedHashMap = 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)
}
}