Как я могу избежать мигания обновления уведомлений при смене кнопки
У меня есть уведомление, поддерживающее воспроизведение, паузу вперед и назад.
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 сделала
Ответы
Ответ 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()
. Это решает мерцание и проблемы с не обновляемыми действиями в уведомлении.