How can I avoid blinking notification update while changing button

本小妞迷上赌 提交于 2019-12-30 03:40:28

问题


I have a Notification, which supports play,pause forward and back.

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

Updating the notification:

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

To avoid blinking on update, I´ve set the builder to a global variable and I reuse it on every update, which works great. but reusing it, means that also all buttons I´ve added are reused and there is no possibility to remove Actions I´ve added before.

The button change only works, if I reinitialize the NotificationCompat.Builder on every update, which means I get the blinking again.

How do I avoid blinking, but letting the button change?

EDIT: Just checked out Rocket Player, they didn´t solve the problem too, but Google Play Music did


回答1:


Like Boris said, the problem is that a new notification will be build every update. My solution covers the same logic, but I use the 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);
        }

keep in mind that mNotificationBuilder is a private field in the class.




回答2:


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

  • retain the instance of the notification inbetween different calls of createNotification.
  • set this instance to null every time it is removed from the notification bar.
  • do the following code:

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 no blinking will appear:

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

PS: I also faced a problem that if I executed setLatestEventInfo the large and small icons got scrwed up. That's 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 Adnroid ccode this line mNotification.icon = 0; disables the icon screw up.




回答3:


I know that this is a rather old question, but since I didn't found a solution anywhere else, I thought answering this now might help others with the same problem.

This problem is kind of tricky to begin with. I encountered it today as well, and being my stubborn self, I found a solution after searching and trying for a while.

How to solve this problem:

In order to be compatible with API-Levels lower than 19, my solution is to use the NotificationCompat classes from the support-library.

As suggested by others, I keep the reference to the NotificationCompat.Builder for as long as the notification is required. The actions I use in my Notification are only added upon initial creation of the Builder, and those actions that will change depending on the situation, I also store in a private member of the service. Upon change, I re-use the Builder object and adjust the NotificationCompat.Action object according to my needs. Then I call the Builder.getNotification() or Builder.build() method, depending on API-level (probably not necessary due to the support-libs, but I didn't check that. If I can omit that, please write a comment, so I can improve my code ;)

Here's an example code of what 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's 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's 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 convenience methods that simply create the PendingIntent objects.

This method is then called when I need to update the notification using the NotificationManager, as well as handed over to the service's startForeground() method. This solves the flickering and the problems with the not updatable actions in the notification.



来源:https://stackoverflow.com/questions/19025056/how-can-i-avoid-blinking-notification-update-while-changing-button

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