2011-10-02 7 views
12

Ok, quindi sto lavorando ad un AppWidget che controlla il livello della batteria e lo visualizza su un TextView. Il mio codice è simile al seguente:ACTION_BATTERY_CHANGED sparando come un matto

public class BattWidget extends AppWidgetProvider { 

private RemoteViews views = new RemoteViews("com.nickavv.cleanwidgets", R.layout.battlayout); 

@Override 
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int appWidgetIds[]) { 
    final int N = appWidgetIds.length; 
    context.getApplicationContext().registerReceiver(this,new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 
    for (int i = 0; i < N; i++) { 
     int appWidgetId = appWidgetIds[i]; 
     appWidgetManager.updateAppWidget(appWidgetId, views); 
    } 
} 

@Override 
public void onReceive(Context context, Intent intent) { 
    super.onReceive(context, intent); 
    Log.d("onReceive", "Received intent " + intent); 
    if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { 
     Integer level = intent.getIntExtra("level", -1); 
     views.setTextViewText(R.id.batteryText, level+"%"); 
     AppWidgetManager myAWM = AppWidgetManager.getInstance(context); 
     ComponentName cn = new ComponentName(context, AirWidget.class); 
     onUpdate(context, myAWM, myAWM.getAppWidgetIds(cn)); 
    } 
} 
} 

e sto ottenendo preoccupato perché non appena mi cade il widget sul mio homescreen comincia sparando circa 100 di quelli Log chiama un secondo, dicendo che sta ricevendo ACTION_BATTERY_CHANGED. Questo non dovrebbe essere trasmesso solo per ogni diminuzione percentuale? In realtà ha causato il ritardo dell'intero programma di avvio, ho dovuto disinstallarlo. Non può essere giusto.

+0

Non so davvero nulla su questo, ma vale la pena creare un servizio per monitorare la batteria e inviarlo al Widgit ad intervalli predefiniti? – mAndroid

risposta

23

Il mio codice è simile al seguente:

Non è possibile registrare un BroadcastReceiver da un altro BroadcastReceiver e ottenere risultati affidabili. Android interromperà il tuo processo, perché non pensa che qualcosa sia in esecuzione. L'unico modo per ascoltare ACTION_BATTERY_CHANGED sarà registrare quel destinatario da un'attività o un servizio.

Non si suppone che questo sia trasmesso solo per ogni diminuzione percentuale?

Dove lo vedi documentato? AFAIK, ACTION_BATTERY_CHANGED verrà trasmesso ogni volta che l'hardware si sente come esso. Inoltre, tieni presente che altri dati cambiano all'interno di quello Intent, ad esempio la temperatura.

Se si desidera implementare questo widget dell'app, non registrare per ACTION_BATTERY_CHANGED come si. Invece:

  • Consente all'utente di scegliere un periodo di polling tramite SharedPreference (ad es., Una volta al minuto, una volta ogni 15 mintui)
  • Usa AlarmManager per darvi il controllo su quel periodo di interrogazione tramite un getBroadcast()PendingIntent
  • In quel BroadcastReceiver, chiamare registerReceiver() per ACTION_BATTERY_CHANGEDma con un null BroadcastReceiver, in modo da restituire a voi l'ultimo Intent che è stato trasmesso per l'azione (nota: sarà ancora bisogno di utilizzare getApplicationContext() per questo)
  • usa AppWidgetManager per aggiornare le istanze di widget app con il livello della batteria tirato fuori dalla Intent è stato recuperato nel precedente passo (nota: se si sta configurando tutti di essere la stessa, non è necessario per scorrere gli ID - utilizzare la updateAppWidget() che prende una ComponentName come parametro)

Questo ha diversi vantaggi:

  1. non ti importa quante volte ACTION_BATTERY_CHANGED viene trasmesso
  2. l'utente ottiene per controllare la quantità di batterie si consumano facendo questi controlli (dovrebbe essere trascurabile se si mantiene il tempo di risposta per un minuto o più)
  3. tuo processo può essere tranquillamente termi NATed tra sondaggi, rendendo così meno probabile che gli utenti vi attaccheranno con assassini di attività e semi-permanente rovinare la vostra applicazione
+2

Questo non può essere il modo migliore per farlo. Ho visto un sacco di widget della batteria closed-source che aggiornano le loro informazioni non appena si verifica un cambiamento (BattStatt è un buon esempio). Non ne ho mai visto uno che offra all'utente un intervallo di aggiornamento. I widget a livello di batteria dovrebbero essere sempre precisi. – Nick

+1

@Nick: "Questo non può essere il modo migliore per farlo" - hai diritto alla tua opinione. "Ho visto un sacco di widget di batterie closed-source che aggiornano le loro informazioni non appena si verifica un cambiamento" - che fanno sprecando un sacco di RAM mantenendo un servizio in memoria tutto il tempo. Gli utenti pensano che gli sviluppatori che lo fanno siano degli idioti, perché è il motivo per cui gli assassini di attività sono così popolari e il sistema operativo deve eliminare in modo proattivo tali servizi. – CommonsWare

+0

@Nick: "I widget a livello di batteria devono essere sempre precisi" - poiché il livello della batteria non cambia in modo particolarmente frequente, un'architettura di polling può essere più che sufficientemente accurata, evitando l'impatto RAM e l'inaffidabilità intrinseca di mantenere un servizio intorno tutto il tempo. – CommonsWare

0

Bene, il vostro onUpdate sta registrando la propria classe come ricevitore per l'intento BatteryInfo. Questo intento viene quindi immediatamente attivato per le prime informazioni. Il tuo onReceive chiama di nuovo il tuo onUpdate. Chiamiamo questo ciclo. Quindi i 100 registri al secondo ...

Problemi correlati