Okay, so I’m working on an AppWidget that checks the battery level and displays it on a TextView. My code looks like this:
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));
}
}
}
And I’m getting concerned because as soon as I drop the widget onto my homescreen it begins firing off about 100 of those Log calls a second, saying it’s receiving ACTION_BATTERY_CHANGED. Isn’t this only supposed to be broadcast for each percent decrease? It actually caused my entire launcher to lag, I had to uninstall it. That can’t be right.
You cannot register a
BroadcastReceiverfrom anotherBroadcastReceiverand get reliable results. Android will terminate your process, because it doesn’t think anything is running. The only way to listen forACTION_BATTERY_CHANGEDwill be to register that receiver from an activity or a service.Where do you see that documented? AFAIK,
ACTION_BATTERY_CHANGEDwill be broadcast whenever the hardware feels like it. Also, bear in mind that other data changes within thatIntent, such as temperature.If you want to implement this app widget, do not register for
ACTION_BATTERY_CHANGEDthe way you are. Instead:SharedPreference(e.g., once a minute, once every 15 mintues)AlarmManagerto give you control on that polling period via agetBroadcast()PendingIntentBroadcastReceiver, callregisterReceiver()forACTION_BATTERY_CHANGEDbut with anullBroadcastReceiver, as this will return to you the lastIntentthat was broadcast for that action (note: you will still need to usegetApplicationContext()for this)AppWidgetManagerto update your app widget instances with the battery level pulled out of theIntentyou retrieved in the preceding step (note: if you are setting them all to be the same, you do not need to iterate over the IDs — use theupdateAppWidget()that takes aComponentNameas a parameter)This has several advantages:
ACTION_BATTERY_CHANGEDis broadcast