Vajira Lasantha Vajira Lasantha - 3 months ago 22
Android Question

Android BroadcastReceiver not updating Widget [FIXED]

UPDATE: Fixed using @user13 answer.

Fist of all I tried all the methods which I found on stackoverflow and non of them worked.

I'm developing a battery monitoring app and it contains some widgets to display information. I use a common receiver called

BatteryUpdateReceiver
to listen to
ACTION_BATTERY_CHANGED
event. I use this receiver to update a widget which shows current battery level. But for some reasons it does not update the widget. I tried many ways but could not figure out whats's wrong. My code is given below.

BatteryUpdateReceiver.java

public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) {
Log.i(TAG, "Receiver ACTION_BATTERY_CHANGED fired");

RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget);

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
ComponentName thisWidget = new ComponentName(context.getApplicationContext(), BatteryWidget.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int i=0; i < allWidgetIds.length; i++) {
Log.i(TAG, "WID ID: " + allWidgetIds[i]);
appWidgetManager.updateAppWidget(allWidgetIds[i], remoteViews);
}
}
}


BatteryWidget.java

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);

Log.i(TAG, "onUpdate: ");

int currentLevel = calculateBatteryLevel(context);
if (batteryChanged(currentLevel)) {
batteryLevel = currentLevel;
Log.i(TAG, "onUpdate: Battery level changed");
}
updateViews(context);
}

private boolean batteryChanged(int currentLevelLeft) {
return (batteryLevel != currentLevelLeft);
}

private int calculateBatteryLevel(Context context) {
Log.i(TAG, "calculateBatteryLevel: ");

Intent batteryIntent = context.getApplicationContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
return level * 100 / scale;
}

private void updateViews(Context context) {
Log.i(TAG, "updateViews: ");

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setTextViewText(R.id.batteryText, batteryLevel + "%");

ComponentName componentName = new ComponentName(context, BatteryWidget.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(componentName, views);
}


AndroidManifest.xml

<receiver android:name=".lib.receivers.BatteryUpdateReceiver" android:enabled="true" />

<receiver android:name=".widget.BatteryWidget" android:label="@string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider" android:resource="@xml/batterywidgetinfo" />
</receiver>


I register BatteryUpdateReceiver using a service when device boot up.

IntentFilter filterBattery = new IntentFilter();
filterBattery.addAction(Intent.ACTION_BATTERY_CHANGED);
this.mBatteryStatusReceiver = new BatteryUpdateReceiver();
getApplicationContext().registerReceiver(this.mBatteryStatusReceiver, filterBattery);
Log.i(TAG, "Receiver ACTION_BATTERY_CHANGED registered by Service");


I can confirm that
BatteryUpdateReceiver
works because it logs widget id. Also if I will put a receiver inside
BatteryWidget
, then the widget gets updated. Can someone tell me what am I missing here? I know I can override
onReceive()
method in
BatteryWidget
class. But how can I archive it this way?

Thanks!

Answer

You should send an ACTION_APPWIDGET_UPDATE broadcast from your receiver, rather than calling updateAppWidget() directly.

Something like this:

@Override
public void onReceive(Context context, Intent intent) {
    AppWidgetManager widgetManager = AppWidgetManager.getInstance(getApplicationContext());
    int[] appWidgetIds = widgetManager.getAppWidgetIds(new ComponentName(context, BatteryWidget.class));

    Intent updateIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, getApplicationContext(), BatteryWidget.class);
    updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);

    sendBroadcast(updateIntent);
}
Comments