Подтвердить что ты не робот

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

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

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 сделала

4b9b3361

Ответ 1

Как сказал Борис, проблема в том, что каждое обновление будет создаваться новым уведомлением. Мое решение охватывает ту же логику, но я использую 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 является частным полем в классе.

Ответ 2

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

  • сохранить экземпляр уведомления между различными вызовами 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;

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

Ответ 3

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

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

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

Чтобы быть совместимым с уровнями 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 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...
}

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

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