2010-08-31 12 views
10

Sto sviluppando un'applicazione con un servizio che mostra l'avanzamento di un timer nell'area di notifica (con una barra di avanzamento e un testo). Ho estratto sotto un esempio più semplice con lo stesso problema.Uso di memoria enorme nelle notifiche

Il codice del servizio:

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

Il codice del 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); 
    } 
} 

Il problema è l'enorme utilizzo della memoria. Ecco l'output 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 

Penso che sia troppa memoria e dopo un po 'si blocca telefono con questa uscita:

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 

Qualcuno sa come posso farlo senza usare tanti memoria ?

Grazie!

+0

vede un bug aperto sul tema: http://code.google.com/p/android/issues/detail?id=13941 –

risposta

2

Provare a utilizzare DDMS per scaricare le allocazioni, che dovrebbe mostrare quali oggetti vengono allocati e dove.

La mia ipotesi è che la barra di avanzamento stia assegnando alcune bitmap su ogni chiamata a setProgressBar (5 volte al secondo) ed è ciò che sta sfogliando la memoria. Ciò che non è chiaro è il motivo per cui si sta esaurendo - il GC sembra prenderlo in mano, quindi qualcosa deve perdere.

+1

I ho usato una barra di avanzamento nella notifica una volta e ho notato che il telefono è diventato molto lento quando ho provato ad aggiornare i progressi. Quindi, ho dovuto ridurre la frequenza di aggiornamento molto. –

+0

Sì! Era anche la mia soluzione, ma non so come evitare o ridurre quel comportamento. – Urizev

10

Mi sono imbattuto nello stesso problema ... Sembra che se non "cache" il RemoteView e la notifica nel servizio, ma ricrearli da zero nella routine di "aggiornamento" questo problema scompare. Sì, lo so che non è efficiente, ma almeno il telefono non si riavvia dopo 10-15 minuti perché ha esaurito la memoria.

+0

Grazie, sembra fare il trucco. – plouh

+0

Ho avuto esattamente lo stesso problema in cui i miei telefoni si sono bloccati (legenda HTC) o parte del sistema operativo si è bloccato (Sony Ericsson Xperia Mini Pro). Ricreare RemoteView su ciascun aggiornamento ha risolto il problema. – slott

+0

Trucco molto bello, grazie – NullPointer

1

Il problema con questa soluzione alternativa è che se si tratta di una notifica in corso, "salterà" sulla barra di stato e sul riquadro delle notifiche man mano che vengono aggiornate altre notifiche in corso.

Ho provato diverse cose, incluso dichiarare i membri RemoteView e Notification come volatili (perché RemoteView è cross-thread), che sembrava funzionare, ma rallentava solo il problema.

Quello su cui ho optato è stato l'utilizzo di un choke member e il "cacheing" di RemoteView e Notification fino a X volte, per poi ricrearli.

Quando i membri sono impostati su null, la piccola perdita sembra essere stata liberata.

0

Ho avuto un problema simile. Ho avuto un Service che ha presentato uno Notification con una barra di avanzamento che corrisponde a un download di file. L'app si arrestava in modo anomalo con uno OutOfMemoryError, circa dieci secondi dopo che l'utente ha fatto clic su Notification portandoli all'app.

Ho trovato che l'aggiunta di .setOngoing(true); al Builder risolve questo problema.

setOngoing NotificationCompat.Builder pubblico (boolean in corso)

impostare se si tratta di una notifica in corso. notifiche in corso differiscono da regolari notifiche nei seguenti modi:

  • notifiche in corso sono ordinati al di sopra delle notifiche regolari nel pannello di notifica.

  • Le notifiche in corso non hanno un pulsante di chiusura "X" e non sono interessate dal pulsante "Cancella tutto".

Esempio:

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); 
Problemi correlati