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.

Rajesh Loganathan
  • 11,129
  • 4
  • 78
  • 90
cottonBallPaws
  • 21,220
  • 37
  • 123
  • 171

4 Answers4

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);
Community
  • 1
  • 1
dbro
  • 1,718
  • 1
  • 20
  • 34
  • 1
    You should use `setWhen(Calendar.getInstance().getTimeInMillis())` instead of `setWhen(0)`. –  Dec 23 '12 at 00:39
  • 2
    @user1521536 Why should we do it like that? – Patrick R. Jun 24 '13 at 16:19
  • 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. – Wolfram Rittmeyer Oct 27 '14 at 22:48
  • @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;` – Sufian Oct 29 '14 at 13:59
  • @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. – Wolfram Rittmeyer Oct 30 '14 at 17:00
  • @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)`. – Sufian Oct 31 '14 at 07:00
  • 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. – Wolfram Rittmeyer Oct 31 '14 at 09:12
  • @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. :) – Sufian Nov 06 '14 at 07:28
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)
Warpzit
  • 27,966
  • 19
  • 103
  • 155
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.

Community
  • 1
  • 1
derflocki
  • 863
  • 1
  • 11
  • 19
  • Did you manage to get rid of flashing after setting startForeground() and then using mNotificationManager.notify() on the same notification? – Warlock Jul 10 '13 at 12:04
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());
Community
  • 1
  • 1
Philipp E.
  • 3,296
  • 3
  • 34
  • 52