Как я могу избежать мигания обновления уведомлений при изменении кнопки

У меня есть уведомление, которое поддерживает воспроизведение, паузу вперед и назад.

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

Обновление уведомления:

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

Чтобы не мигать при обновлении, я установил построитель в глобальную переменную, и я использую его при каждом обновлении, что отлично работает. Но повторное использование этого означает, что все кнопки, которые я добавил, повторно используются, и нет возможности удалить действия, которые я добавил ранее.

Изменение кнопки работает только в том случае, если я обновляю NotificationCompat.Builder при каждом обновлении, что означает, что я снова моргаю.

Как избежать мигания, но если кнопка изменится?

EDIT: Только что проверил Rocket Player, они также не решили проблему, но Google Play Music

Solutions Collecting From Web of "Как я могу избежать мигания обновления уведомлений при изменении кнопки"

Как сказал Борис, проблема в том, что новое уведомление будет создано каждое обновление. Мое решение охватывает ту же логику, но я использую NotificationBuilder

Вот код:

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

mNotificationBuilder в виду, что mNotificationBuilder – это частное поле в классе.

Проблема в том, что вы создаете новое уведомление каждый раз, когда хотите обновить. У меня была такая же проблема, и я исправил ее, когда сделал следующее:

  • createNotification экземпляр уведомления между различными вызовами createNotification .
  • Установите этот экземпляр равным null при каждом удалении из панели уведомлений.
  • Выполните следующий код:

Код:

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

И теперь, когда вы вызываете notify не будет мигать:

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

PS: Я также столкнулся с проблемой, что если бы я выполнил setLatestEventInfo то большие и маленькие значки разрастались. Вот почему я сделал:

 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; 

Заглядывая в Adnroid ccode эту строку mNotification.icon = 0; Отключает значок.

Я знаю, что это довольно старый вопрос, но поскольку я не нашел решения нигде, я думал, что ответ на этот вопрос теперь может помочь другим с той же проблемой.

Для начала эта проблема довольно сложная. Сегодня я столкнулся с этим, и, будучи моим упрямым «я», я нашел решение после того, как искал и пытался какое-то время.

Как решить эту проблему:

Чтобы быть совместимым с уровнями API ниже 19, мое решение состоит в том, чтобы использовать классы NotificationCompat из библиотеки поддержки.

Как было предложено другими, я сохраняю ссылку на NotificationCompat.Builder до тех пор, пока требуется уведомление. Действия, которые я использую в своем уведомлении, добавляются только при первоначальном создании Builder , и те действия, которые будут меняться в зависимости от ситуации, я также храню в частном члене службы. После изменения я повторно использую объект Builder и настраиваю объект NotificationCompat.Action соответствии с моими потребностями. Затем я вызываю метод Builder.getNotification() или Builder.build() , в зависимости от уровня API (возможно, не обязательно из-за поддержки-libs, но я не проверял это. Если я могу это пропустить, напишите Комментарий, поэтому я могу улучшить свой код;)

Вот пример кода того, что я только что описал выше:

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

Переменные foregroundNotificationBuilder , pauseAction и foregroundNotificationPauseButton являются частными членами класса сервиса. getPendingIntent...() – это удобные методы, которые просто создают объекты PendingIntent .

Этот метод затем вызывается, когда мне нужно обновить уведомление с помощью NotificationManager , а также передать метод startForeground() службы. Это решает мерцание и проблемы с не обновляемыми действиями в уведомлении.