2010-08-31 12 views
10

Estoy desarrollando una aplicación con un servicio que muestra el progreso de un temporizador en el área de notificación (con una barra de progreso y un texto). He extraído debajo un ejemplo más simple con el mismo problema.Gran uso de memoria en las notificaciones

El código del servicio:

public class TNService extends Service { 
    private NotificationManager nm; 
    private Notification notification; 
    private RemoteViews remoteView; 

    @Override 
    public void onCreate() { 
     nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); 
     notification = new Notification(android.R.drawable.stat_sys_download, 
       "My notification", 
       System.currentTimeMillis()); 
     remoteView = new RemoteViews(this.getPackageName(), 
       R.layout.notification); 
     remoteView.setImageViewResource(R.id.icon, android.R.drawable.stat_sys_download); 
     remoteView.setTextViewText(R.id.text, ""); 
     remoteView.setProgressBar(R.id.progress, 100, 0, false); 
     notification.flags = Notification.FLAG_NO_CLEAR; 
     notification.contentView = remoteView; 
     notification.contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, 
       TNActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); 

     Timer timer = new Timer(); 
     timer.schedule(new TNTask(this), 0, 200); 
    } 

    @Override 
    public IBinder onBind(Intent arg0) { 
     return null; 
    } 

    public void updateNotification(int progress) { 
     remoteView.setProgressBar(R.id.progress, 1000, progress, false); 
     remoteView.setTextViewText(R.id.text, "Progress: " + progress); 
     nm.notify(0, notification); 
    } 
} 

El código de la TimerTask:

public class TNTask extends TimerTask { 
    private TNService service; 
    private int progress; 

    public TNTask(TNService s) { 
     this.service = s; 
     this.progress = 0; 
    } 

    @Override 
    public void run() { 
      progress = (progress + 1) % 1000; 
     this.service.updateNotification (progress); 
    } 
} 

El problema es el enorme uso de la memoria. Aquí está la salida Logcat:

D/dalvikvm(11985): GC_EXPLICIT freed 1258 objects/84016 bytes in 1157ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 52216 objects/1900968 bytes in 130ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 49465 objects/1805248 bytes in 125ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 53106 objects/1909992 bytes in 134ms 
D/dalvikvm(12008): GC_EXPLICIT freed 1604 objects/100944 bytes in 90ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 53011 objects/1937160 bytes in 135ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 49806 objects/1817992 bytes in 143ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 49016 objects/1769536 bytes in 135ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 53509 objects/1941064 bytes in 145ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 49895 objects/1842312 bytes in 146ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 48728 objects/1774496 bytes in 150ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 47557 objects/1701976 bytes in 146ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 53540 objects/1903808 bytes in 156ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 48997 objects/1784048 bytes in 158ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 48326 objects/1776864 bytes in 158ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 47566 objects/1742488 bytes in 169ms 
D/dalvikvm( 85): GC_FOR_MALLOC freed 47606 objects/1703416 bytes in 170ms 
D/dalvikvm( 162): GC_EXPLICIT freed 11238 objects/641368 bytes in 1064ms 

Creo que es demasiada memoria y después de un tiempo el teléfono se cuelga con esta salida:

D/dalvikvm( 85): GC_FOR_MALLOC freed 0 objects/0 bytes in 241ms 
I/dalvikvm-heap( 85): Clamp target GC heap from 24.008MB to 24.000MB 
I/dalvikvm-heap( 85): Grow heap (frag case) to 24.000MB for 52-byte allocation 
I/dalvikvm-heap( 85): Clamp target GC heap from 26.008MB to 24.000MB 
D/dalvikvm( 85): GC_FOR_MALLOC freed 0 objects/0 bytes in 241ms 
I/dalvikvm-heap( 85): Clamp target GC heap from 24.008MB to 24.000MB 
I/dalvikvm-heap( 85): Grow heap (frag case) to 24.000MB for 24-byte allocation 
I/dalvikvm-heap( 85): Clamp target GC heap from 26.008MB to 24.000MB 
D/dalvikvm( 85): GC_FOR_MALLOC freed 0 objects/0 bytes in 247ms 
I/dalvikvm-heap( 85): Clamp target GC heap from 24.009MB to 24.000MB 
I/dalvikvm-heap( 85): Grow heap (frag case) to 24.000MB for 28-byte allocation 
I/dalvikvm-heap( 85): Clamp target GC heap from 26.009MB to 24.000MB 
D/dalvikvm( 85): GC_FOR_MALLOC freed 0 objects/0 bytes in 247ms 
I/dalvikvm-heap( 85): Clamp target GC heap from 24.009MB to 24.000MB 

alguien sabe cómo puedo hacerlo sin utilizar tantos memoria ?

Gracias!

+0

ve un error accesible sobre el tema: http://code.google.com/p/android/issues/detail?id=13941 –

Respuesta

2

Pruebe usar DDMS para eliminar las asignaciones, esto debería mostrarle qué objetos se asignan y dónde.

Supongo que la barra de progreso está asignando algunos mapas de bits en cada llamada a setProgressBar (5 veces por segundo) y eso es lo que está agitando la memoria. Lo que no está claro es por qué se está acabando, el GC parece estar retomando, entonces algo debe estar goteando.

+1

I usé una barra de progreso en la notificación una vez, y experimenté que el teléfono se puso realmente lento cuando intenté actualizar el progreso. Entonces, tuve que reducir la frecuencia de actualización mucho. –

+0

¡Sí! También fue mi solución, pero no sé cómo evitar o reducir ese comportamiento. – Urizev

10

Me encontré con el mismo problema ... Parece que si no "guardo" el RemoteView y la Notificación en el servicio, sino que los vuelvo a crear desde cero en la rutina de "actualización", este problema desaparece. Sí, sé que no es eficiente, pero al menos el teléfono no se reinicia después de 10-15 minutos porque está sin memoria.

+0

Gracias, parece hacer el truco. – plouh

+0

Tuve el mismo problema exacto en el que mis teléfonos se bloqueaban (HTC legend) o se bloqueaban parte del sistema operativo (Sony Ericsson Xperia Mini Pro). Volver a crear RemoteView en cada actualización resolvió el problema. – slott

+0

Muy buen truco, gracias – NullPointer

1

El problema con esta solución alternativa es que si se trata de una notificación en curso, se "saltará" en la barra de estado y el panel de notificaciones a medida que se actualicen otras notificaciones en curso.

He intentado varias cosas, incluida la declaración de los miembros RemoteView y Notificación como volátiles (porque RemoteView es de tipo cruzado), lo que pareció funcionar, pero solo ralentizó el problema.

Lo que establecí fue utilizar un elemento de estrangulación, y "almacenar en caché" la RemoteView y la Notificación hasta X veces, y luego volver a crearlas.

Cuando sus miembros se establecen en nulo, la pequeña fuga parece liberarse.

0

Tuve un problema similar. Tenía un Service que presentaba un Notification con una barra de progreso que correspondía a la descarga de un archivo. La aplicación se bloqueará con un OutOfMemoryError, alrededor de diez segundos después de que el usuario hizo clic en Notification llevándolos a la aplicación.

He encontrado que agregar .setOngoing(true); al Constructor ha solucionado este problema.

setOngoing NotificationCompat.Builder pública (booleano en curso)

Permite configurar si se trata de una notificación en curso. notificaciones en curso se diferencian de las notificaciones regulares de las siguientes maneras:

  • notificaciones en curso están ordenados por encima de las notificaciones regulares en el panel de notificaciones.

  • Las notificaciones en curso no tienen un botón de "Cerrar" y no se ven afectadas por el botón "Borrar todo".

Ejemplo:

NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setAutoCancel(true) 
                 .setDefaults(Notification.DEFAULT_ALL) 
                 .setContentTitle("Downloading").setContentText("Download in progress...) 
                  .setSmallIcon(android.R.drawable.stat_sys_download) 
                  .setSound(null) 
                  .setDefaults(0) 
                  .setOngoing(true); 
Cuestiones relacionadas