Two or more Foreground Notification with Progress is replacing each other while updating its progress

北慕城南 提交于 2020-07-30 08:02:40

问题


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 there will be two or more foreground service that will run. Everything works fine but what I want is to show all task's notification with progress with this code.

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

But unfortunately the notification just get overwrites, but if I removed the startForeground() then everything works fine as it shows multiple progress notification according to how many task is ongoing but the system may kill the process if gets low memory that is why I wanted it to run in foreground. So how am I able to show a number of notification that is equal to the number of on going task in Foreground?


回答1:


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

}



回答2:


Use different id for different notification. In this code, you are using same default id so new notification is replacing old one.




回答3:


You should pass different Id to get different notification.

In Your Code:

Use getId() method to get different Id for each notification:

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.

For android O you need notification channel:

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



回答4:


At last I figure it out how to do it. First I needed to run it inside a onCreate with a little delay.

 @Override
public void onCreate (){
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
                startForeground(requestCode, getMyActivityNotification("",completedParts,totalSize));
        }
    },500);

}

Then create a notification provider method.

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

}

Then updating notification progress should be separated from calling a foreground.

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


来源:https://stackoverflow.com/questions/51243494/two-or-more-foreground-notification-with-progress-is-replacing-each-other-while

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!