How to properly update a notification post api 11?
Asked Answered
U

4

18
  • Before Notification.Builder came into existence the way to update a notification that was already in the notification tray was to call setLatestEventInfo() and then send the notification back through the NotificationManager.notify() call with an ID that matches the first notify() call you made.

  • Now setLatestEventInfo() is deprecated with the message: Use Notification.Builder instead. But I cannot find any documentation about how to properly update a notification using Notification.Builder.

  • Are you just suppose to recreate a new Notification instance every time you need to update the notification? Then simply pass that to NotificationManager.notify() with the ID you used before?

  • It seems to work but I wanted to see if anyone had any official verification that this is the new "way to do this"?

There real reason I am asking this is because in Android 4.1.1 Jelly Bean, the notification now flashes everytime notify() is called. When updating a progress bar with setProgress() this looks really bad and makes it hard to tap on the notification. This was not the case in 4.1 or previous versions. So I want to make sure I am doing this correctly before I file a bug.

Unfruitful answered 16/7, 2012 at 21:40 Comment(2)
where are you updating your notification from? A service I assume..?Hoist
can you also add the code you use for creating/updating the notification?Hoist
P
20

I resolved this issue by calling setWhen(0) on my Notification.Builder. It seems Android's default value for this argument doesn't suit updating bits of the notification view without the entire notification fading out / in.

Notification.Builder builder = new Notification.Builder(c)
                .setContentTitle("Notification Title")
                .setSmallIcon(R.drawable.ic_notification_icon)
                .setProgress(max_progress,current_progress,false)
                .setWhen(0);
                notification = builder.getNotification();

mNotificationManager.notify(NOTIFICATION_ID, notification);

Update:

As WolframRittmeyer stated, using when=0 is not an elegant way. I formed a solution like following:

if(mNotif == null) {
//either setting mNotif first time
//or was lost when app went to background/low memory
    mNotif = createNewNotification();
}
else {
    long oldWhen = mNotif.when;
    mNotif = createNewNotification();
    mNotif.when = oldWhen;
}
mNotificationManager.notify(NOTIFICATION_ID, mNotif);
Psychometrics answered 18/9, 2012 at 22:50 Comment(8)
You should use setWhen(Calendar.getInstance().getTimeInMillis()) instead of setWhen(0).Incurrent
@Incurrent Why should we do it like that?Burnout
Thanks. Your answer got me to the correct solution. But you should use a meaningful time for the event. If the update uses the same meaningful time, the notification won't blink/flash. Only when the timestamp changes (which without setting when explicitly always will happen), your notification flashes/blinks. Keep in mind that the when field might be used for sorting - now or in the future. Setting it to 0 thus could cause all kind of unexpected trouble.Radford
@WolframRittmeyer I think we could avoid getting time from System (as it only tends to show blinking effect) by doing like this: long oldWhen = mNotif.when; mNotif = createNewNotification(); mNotif.when = oldWhen;Needleful
@sufian Well mNotif might go out of scope (e.g. when user swipes activity away). It depends on what you have. If you have a long running service, this of course is no issue. Still, IMHO every notification has a natural starting timestamp. E.g. when the user started playing a song. Or the timestamp of the gcm message, or the start of the day, or the time the goal was scored, or... If you always use this natural timestamp, all is fine.Radford
@WolframRittmeyer I think it's a bad practice to not cancel a notification when its Activity is swiped away. Even if we don't handle it, we could add a simple check like if (mNotif != null).Needleful
Of course the notification shouldn't be canceled! I never proposed to do that! But if your app goes away your member mNotif goes with it. Thus you cannot update it without flicker. That's why I don't think member based solutions are a good way to solve the problem.Radford
@WolframRittmeyer I think you misunderstood. I said that if we lose the mNotif field, we can create a new Notification (there's no other way for such a situation) but if we have mNotif set then we should use its when property (to avoid flickering in normal cases). I will update the answer or write my own answer including this trick. :)Needleful
D
2

What you are doing is correct, you're just missing the flags you can set. I don't know your particular notification implementation but you might consider using:

setOngoing(boolean ongoing)

or

setOnlyAlertOnce(boolean onlyAlertOnce)
Darlleen answered 9/8, 2012 at 14:0 Comment(0)
C
1

I'm guessing (since I had the same trouble just now) that you are using a RemoteView in your notification. I managed to update the notification without it flashing like this:

RemoteViews views;
if( this.mNotification == null) {
    views = new RemoteViews(getPackageName(), R.layout.notification);
    this.mNotification = new Notification.Builder(this)
        .setContent(views)
        .setSmallIcon(R.drawable.status_icon)
        .setContentIntent(mNotificationAction)
        .setOngoing(true)
        .setOnlyAlertOnce(true)
        .getNotification();
} else {
    views = this.mNotification.contentView;
}

Thanks to @seanmonstar for answering Refresh progress bar in notification bar.

Charter answered 14/9, 2012 at 13:43 Comment(1)
Did you manage to get rid of flashing after setting startForeground() and then using mNotificationManager.notify() on the same notification?Otterburn
B
0

The solution described here works well: Updating an ongoing notification quietly

The key is to use to reuse the builder and setOnlyAlertOnce(true):

if (firstTime) {
  mBuilder.setSmallIcon(R.drawable.icon)
  .setContentTitle("My Notification") 
  .setOnlyAlertOnce(true); 
  firstTime = false;
} 
mBuilder.setContentText(message)
.setProgress(100, progress, true);

mNotificationManager.notify(mNotificationId, mBuilder.build());
Bradlybradman answered 21/10, 2013 at 17:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.