¿Cómo puedo evitar la actualización de notificaciones parpadeantes mientras cambia el botón
Tengo una notificación, que apoya el juego, pausa adelante y detrás.
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; }
Actualización de la notificación:
- Icono de muestra de Android en la barra de estado
- Cómo mostrar el recuento de notificaciones en el icono del lanzador de aplicaciones
- Los dispositivos Android 4.x reciben mensajes GCM, pero los dispositivos Android 2.3
- Cómo crear una notificación en la barra de estado mediante un mensaje de teléfono
- Android Notification no está mostrando Color Icon en Marshmallow
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)); }
Para evitar el parpadeo en la actualización, he establecido el constructor en una variable global y lo vuelvo a usar en cada actualización, lo cual funciona muy bien. Pero reutilizarlo, significa que también todos los botones que he agregado se reutilizan y no hay posibilidad de eliminar las acciones que he añadido antes.
El cambio de botón sólo funciona si reinicio el NotificationCompat.Builder en cada actualización, lo que significa que vuelvo a parpadear.
¿Cómo evito parpadear, pero dejar que el botón cambie?
EDIT: Acaba de salir de Rocket Player, no solucionaron el problema también, pero Google Play Music no
- Color androide del fondo de la notificación del lollipop
- Cómo mostrar mensajes emergentes sin tener un contexto
- Registro de GCM con dos identificadores de registro de trabajo diferentes
- No hay sonido de notificación personalizado
- Notificación push en Amazon Android
- Cómo dar contador si hay más de una notificación
- ¿Cómo mostrar las notificaciones de Android en la pantalla, así como el icono de la barra de estado?
- Cómo especificar min y / o longitud máxima en RemoteInput
Como Boris dijo, el problema es que una nueva notificación será construir cada actualización. Mi solución cubre la misma lógica, pero uso el NotificationBuilder
…
Aquí está el código:
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); }
Tenga en cuenta que mNotificationBuilder
es un campo privado de la clase.
El problema es que se crea una nueva notificación cada vez que se desea actualizar. Tuve el mismo problema y se corrigió cuando hice lo siguiente:
- Retener la instancia de la notificación entre diferentes llamadas de
createNotification
. - Establezca esta instancia en null cada vez que se quita de la barra de notificación.
- Haga el siguiente código:
Código:
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; }
Y ahora cuando llamas a notify
no parpadeará aparecerá:
manager.notify(0, createNotification(interpret, title, paused));
PS: También me enfrenté a un problema que si setLatestEventInfo
los iconos grandes y pequeños se scrwed. Por eso lo hice:
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;
Mirando en el ccode de Adnroid esta línea mNotification.icon = 0;
Desactiva el icono de tornillo hacia arriba.
Sé que esta es una pregunta bastante antigua, pero como no encontré una solución en ningún otro lugar, pensé que responder a esto ahora podría ayudar a otros con el mismo problema.
Este problema es un poco complicado para empezar. Lo encontré hoy también, y siendo mi auto obstinado, encontré una solución después de buscar y de intentar por un rato.
Cómo resolver este problema:
Para ser compatible con niveles de API inferiores a 19, mi solución es utilizar las clases de NotificationCompat
de la biblioteca de soporte.
Como sugerido por otros, sigo la referencia a la NotificationCompat.Builder
durante el tiempo que se requiere la notificación. Las acciones que utilizo en mi Notificación solo se agregan a la creación inicial del Builder
, y aquellas acciones que cambiarán dependiendo de la situación, también almacenaré en un miembro privado del servicio. Al cambiar, vuelvo a usar el objeto Builder
y ajustar el objeto NotificationCompat.Action
según mis necesidades. Luego llamo al método Builder.getNotification()
o Builder.build()
, dependiendo del nivel de la API (probablemente no es necesario debido a las librerías de soporte, pero no lo compruebo.) Si puedo omitirlo, por favor escriba un Comentario, para que pueda mejorar mi código;)
He aquí un ejemplo de código de lo que acabo de describir:
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... }
Las variables foregroundNotificationBuilder
, pauseAction
y foregroundNotificationPauseButton
son miembros privados de la clase de servicio. Los getPendingIntent...()
son métodos de conveniencia que simplemente crean los objetos PendingIntent
.
A continuación, se llama a este método cuando necesito actualizar la notificación mediante NotificationManager
, así como entregarla al método startForeground()
. Esto soluciona el parpadeo y los problemas con las acciones no actualizables en la notificación.
- Android ¿Cómo se obtiene memoria RAM total en el dispositivo?
- Cómo implementar el patrón "Loading images" (Opacity, Exposure and Saturation) de las nuevas directrices de diseño de materiales de Google