Android BroadcastReceiver 未更新 Widget
Android BroadcastReceiver not updating Widget
最重要的是,我尝试了在 Whosebug 上找到的所有方法,但没有一个有效。
我正在开发一个电池监控应用程序,它包含一些显示信息的小部件。我使用一个名为 BatteryUpdateReceiver
的普通接收器来收听 ACTION_BATTERY_CHANGED
事件。我使用此接收器更新显示当前电池电量的小部件。但由于某些原因,它不会更新小部件。我尝试了很多方法,但无法弄清楚出了什么问题。我的代码如下。
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>
我在设备启动时使用服务注册 BatteryUpdateReceiver。
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");
我可以确认 BatteryUpdateReceiver
有效,因为它记录了小部件 ID。另外,如果我将接收器放在 BatteryWidget
内,那么小部件就会更新。有人能告诉我我在这里想念什么吗?我知道我可以覆盖 BatteryWidget
class 中的 onReceive()
方法。但是我怎样才能这样存档呢?
谢谢!
您应该从接收器发送一个 ACTION_APPWIDGET_UPDATE
广播,而不是直接调用 updateAppWidget()
。
像这样:
@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);
}
在同一个问题上花费了无数个小时之后,我终于找到了解决方案。 @earthw0rmjim 的回答把我推到了一半,但我意识到你不能从 Kotlin 广播接收器调用 sendBroadcast()
。您必须调用广播上下文和应用程序上下文才能发送广播。
这是对我有用的代码,适用于可能希望在 Kotlin 中实现相同目标的任何人。就我而言,MyWidgetProvider
是我用来处理主屏幕小部件的 AppWidgetProvider
class。
override fun onReceive(context: Context, intent: Intent) {
val widgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = widgetManager.getAppWidgetIds(ComponentName(context,MyWidgetProvider::class.java))
val updateIntent = Intent(
AppWidgetManager.ACTION_APPWIDGET_UPDATE,
null,
context,
MyWidgetProvider::class.java
)
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
context.applicationContext.sendBroadcast(updateIntent)
}
最重要的是,我尝试了在 Whosebug 上找到的所有方法,但没有一个有效。
我正在开发一个电池监控应用程序,它包含一些显示信息的小部件。我使用一个名为 BatteryUpdateReceiver
的普通接收器来收听 ACTION_BATTERY_CHANGED
事件。我使用此接收器更新显示当前电池电量的小部件。但由于某些原因,它不会更新小部件。我尝试了很多方法,但无法弄清楚出了什么问题。我的代码如下。
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>
我在设备启动时使用服务注册 BatteryUpdateReceiver。
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");
我可以确认 BatteryUpdateReceiver
有效,因为它记录了小部件 ID。另外,如果我将接收器放在 BatteryWidget
内,那么小部件就会更新。有人能告诉我我在这里想念什么吗?我知道我可以覆盖 BatteryWidget
class 中的 onReceive()
方法。但是我怎样才能这样存档呢?
谢谢!
您应该从接收器发送一个 ACTION_APPWIDGET_UPDATE
广播,而不是直接调用 updateAppWidget()
。
像这样:
@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);
}
在同一个问题上花费了无数个小时之后,我终于找到了解决方案。 @earthw0rmjim 的回答把我推到了一半,但我意识到你不能从 Kotlin 广播接收器调用 sendBroadcast()
。您必须调用广播上下文和应用程序上下文才能发送广播。
这是对我有用的代码,适用于可能希望在 Kotlin 中实现相同目标的任何人。就我而言,MyWidgetProvider
是我用来处理主屏幕小部件的 AppWidgetProvider
class。
override fun onReceive(context: Context, intent: Intent) {
val widgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = widgetManager.getAppWidgetIds(ComponentName(context,MyWidgetProvider::class.java))
val updateIntent = Intent(
AppWidgetManager.ACTION_APPWIDGET_UPDATE,
null,
context,
MyWidgetProvider::class.java
)
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
context.applicationContext.sendBroadcast(updateIntent)
}