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

前端 未结 4 1042
北恋
北恋 2021-01-22 04:15

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

相关标签:
4条回答
  • 2021-01-22 04:21

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

    0 讨论(0)
  • 2021-01-22 04:29

    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));
        }
    }
    
    0 讨论(0)
  • 2021-01-22 04:35

    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());
    
    0 讨论(0)
  • 2021-01-22 04:45

    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)
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题