How can I avoid blinking notification update while changing button

雨燕双飞 提交于 2019-11-30 11:10:29

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.

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.

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.

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