How can I avoid flashing notification updates when a button is changed

I have a notification that supports playback, pause forward and backward.

private static Notification createNotification(String interpret, String title, boolean paused) { // if (builder == null) builder = new NotificationCompat.Builder(context); builder.setPriority(Notification.PRIORITY_MAX); builder.setAutoCancel(false); builder.setContentTitle(title); builder.setContentText(interpret); builder.setOngoing(true); builder.setOnlyAlertOnce(true); builder.setSmallIcon(R.drawable.ic_launcher); builder.setContentIntent(PendingIntent.getActivity(context, 9, new Intent(context, ApplicationActivity.class), Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)); builder.addAction(R.drawable.av_previous, "", PendingIntent.getBroadcast(context.getApplicationContext(), 0, new Intent(NotificationPlayerControlReceiver.MUSIC_PLAYER_INTENT).putExtra("resultcode", NotificationPlayerControlReceiver.PREVIOUS), PendingIntent.FLAG_CANCEL_CURRENT)); if (paused) builder.addAction(R.drawable.av_play, "", PendingIntent.getBroadcast(context.getApplicationContext(), 2, new Intent(NotificationPlayerControlReceiver.MUSIC_PLAYER_INTENT).putExtra("resultcode", NotificationPlayerControlReceiver.PLAY), PendingIntent.FLAG_CANCEL_CURRENT)); else builder.addAction(R.drawable.av_pause, "", PendingIntent.getBroadcast(context.getApplicationContext(), 3, new Intent(NotificationPlayerControlReceiver.MUSIC_PLAYER_INTENT).putExtra("resultcode", NotificationPlayerControlReceiver.PAUSE), PendingIntent.FLAG_CANCEL_CURRENT)); builder.addAction(R.drawable.av_next, "", PendingIntent.getBroadcast(context.getApplicationContext(), 1, new Intent(NotificationPlayerControlReceiver.MUSIC_PLAYER_INTENT).putExtra("resultcode", NotificationPlayerControlReceiver.NEXT), PendingIntent.FLAG_CANCEL_CURRENT)); Notification notification = builder.build(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) notification.tickerView = null; return notification; } 

Notification Update:

  public static void update(String interpret, String title, boolean paused) { NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(0, createNotification(interpret, title, paused)); } 

In order not to blink when updating, I set the builder to a global variable, and I reuse it with every update, which works fine. but reusing it means that all the buttons that I added are reused, and there is no way to remove the actions that I added earlier.

Changing the button works if I reinitialize NotificationCompat.Builder with every update, which means I want to blink again.

How to avoid blinking, but if the button changes?

EDIT: Just checked the Rocket Player, they also didn't solve the problem, but Google Play Music did

+16
android notifications android-notifications
Sep 26 '13 at 9:55 on
source share
3 answers

As Boris said, the problem is that each update will be created with a new notification. My solution covers the same logic, but I'm using NotificationBuilder ...

here is the code:

 if (mNotificationBuilder == null) { mNotificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(iconId) .setContentTitle(title) .setContentText(message) .setLargeIcon(largeIcon) .setOngoing(true) .setAutoCancel(false); } else { mNotificationBuilder.setContentTitle(title) .setContentText(message); } 

remember that mNotificationBuilder is a private field in the class.

+11
Nov 21 '14 at 20:09
source share

The problem is that you create a new notification every time you want to update. I had the same problem and fixed it when I did the following:

  • keep a notification instance between different calls to createNotification .
  • set this instance to null each time you remove it from the notification panel.
  • execute the following code:

the code:

 private static Notification createNotification(String interpret, String title, boolean paused) { if (mNotification == null) { // do the normal stuff you do with the notification builder } else { // set the notification fields in the class member directly ... set other fields. // The below method is deprecated, but is the only way I have found to set the content title and text mNotification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); } return mNotification; } 

And now, when you call notify , it will not blink:

 manager.notify(0, createNotification(interpret, title, paused)); 

PS: I also ran into the problem that if I setLatestEventInfo , the big and small icons were expanding. This is why I did:

 int tmpIconResourceIdStore = mNotification.icon; // this is needed to make the line below not change the large icon of the notification mNotification.icon = 0; // The below method is deprecated, but is the only way I have found to set the content title and text mNotification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); mNotification.icon = tmpIconResourceIdStore; 

Looking into the cnode Adnroid code, this line is mNotification.icon = 0; disables the icon.

+5
Oct 15 '13 at 7:22
source share

I know this is a rather old question, but since I could not find a solution anywhere, I thought that the answer to this question can now help others with the same problem.

For a start, this problem is quite complicated. Today I came across this, and being my stubborn self, I found a solution after searching and trying for some time.

How to solve this problem:

To be compatible with API levels below 19, my solution is to use NotificationCompat classes from the support library.

As suggested by others, I keep a link to NotificationCompat.Builder as long as a notification is required. The actions that I use in my notification are added only after the initial creation of Builder , and those actions that will change depending on the situation, I also store in a private member of the service. After the change, I reuse the Builder object and customize the NotificationCompat.Action object according to my needs. Then I call the Builder.getNotification() or Builder.build() method, depending on the API level (maybe not necessarily due to support for-libs, but I haven’t checked this. If I can skip this, write a comment so that I can improve my code;)

Here is an example of the code I just described above:

 public Notification createForegroundNotification(TaskProgressBean taskProgressBean, boolean indeterminate) { Context context = RewardCalculatorApplication.getInstance(); long maxTime = TaskUtils.getMaxTime(taskEntry); long taskElapsedTime = TaskUtils.calculateActualElapsedTime(taskProgressBean); long pauseElapsedTime = taskProgressBean.getPauseElapsedTime(); int pauseToggleActionIcon; int pauseToggleActionText; PendingIntent pauseToggleActionPI; boolean pauseButton = pauseElapsedTime == 0; if(pauseButton) { pauseToggleActionIcon = R.drawable.ic_stat_av_pause; pauseToggleActionText = R.string.btnTaskPause; pauseToggleActionPI = getPendingIntentServicePause(context); } else { pauseToggleActionIcon = R.drawable.ic_stat_av_play_arrow; pauseToggleActionText = R.string.btnTaskContinue; pauseToggleActionPI = getPendingIntentServiceUnpause(context); } String contentText = context.getString(R.string.taskForegroundNotificationText, TaskUtils.formatTimeForDisplay(taskElapsedTime), TaskUtils.formatTimeForDisplay(pauseElapsedTime), TaskUtils.formatTimeForDisplay(taskProgressBean.getPauseTotal())); // check if we have a builder or not... boolean createNotification = foregroundNotificationBuilder == null; if(createNotification) { // create one foregroundNotificationBuilder = new NotificationCompat.Builder(context); // set the data that never changes...plus the pauseAction, because we don't change the // pauseAction-object, only it data... pauseAction = new NotificationCompat.Action(pauseToggleActionIcon, getString(pauseToggleActionText), pauseToggleActionPI); foregroundNotificationBuilder .setContentTitle(taskEntry.getName()) .setSmallIcon(R.drawable.ic_launcher) .setContentIntent(getPendingIntentActivity(context)) .setOngoing(true) .addAction(R.drawable.ic_stat_action_done, getString(R.string.btnTaskFinish), getPendingIntentServiceFinish(context)) .addAction(pauseAction); } // this changes with every update foregroundNotificationBuilder.setContentText(contentText); if(indeterminate) { foregroundNotificationBuilder.setProgress(0, 0, true); } else { foregroundNotificationBuilder.setProgress((int) maxTime, (int) taskElapsedTime, false); } // if this is not the creation but the button has changed, change the pauseAction data... if(!createNotification && (pauseButton != foregroundNotificationPauseButton)) { foregroundNotificationPauseButton = pauseButton; pauseAction.icon = pauseToggleActionIcon; pauseAction.title = getString(pauseToggleActionText); pauseAction.actionIntent = pauseToggleActionPI; } return (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) ? foregroundNotificationBuilder.getNotification() // before jelly bean... : foregroundNotificationBuilder.build(); // since jelly bean... } 

The variables foregroundNotificationBuilder , pauseAction and foregroundNotificationPauseButton are private members of the service class. The getPendingIntent...() methods are convenient methods that simply create PendingIntent objects.

Then this method is called when I need to update the notification using the NotificationManager , and also pass the startForeground() service method. This solves flickering and issues with non-updating actions in the notification.

+2
May 02 '15 at 1:40 pm
source share



All Articles