【问题标题】:ACTION_BATTERY_CHANGED firing like crazyACTION_BATTERY_CHANGED 疯狂开火
【发布时间】:2011-10-02 06:04:02
【问题描述】:

好的,所以我正在开发一个 AppWidget,它检查电池电量并将其显示在 TextView 上。我的代码如下所示:

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

我开始担心,因为一旦我将小部件放到我的主屏幕上,它就会开始每秒触发大约 100 个这样的 Log 调用,并说它正在接收 ACTION_BATTERY_CHANGED。这不应该只为每减少一个百分比而广播吗?它实际上导致我的整个启动器滞后,我不得不卸载它。这不可能。

【问题讨论】:

  • 对此一无所知,但是否值得设置一项服务来监控电池并以预定义的时间间隔将其反馈给widgit?

标签: android broadcastreceiver android-appwidget battery


【解决方案1】:

我的代码如下所示:

您无法从另一个BroadcastReceiver 注册BroadcastReceiver 并获得可靠的结果。 Android 将终止您的进程,因为它认为没有任何东西在运行。监听ACTION_BATTERY_CHANGED 的唯一方法是从活动或服务中注册该接收器。

这不是应该只针对每减少一个百分比进行广播吗?

您在哪里看到记录在案的? AFAIK,ACTION_BATTERY_CHANGED 将在硬件感觉良好时广播。另外,请记住,Intent 内的其他数据会发生变化,例如温度。

如果你想实现这个应用小部件,不要像你一样注册ACTION_BATTERY_CHANGED。而是:

  • 允许用户通过SharedPreference 选择轮询周期(例如,每分钟一次,每 15 分钟一次)
  • 使用AlarmManager 让您通过getBroadcast() PendingIntent 控制该轮询周期
  • 在该BroadcastReceiver 中,为ACTION_BATTERY_CHANGED 调用registerReceiver() 但使用null BroadcastReceiver,因为这将返回给您最后一个为该操作广播的Intent(注意:您仍然需要为此使用getApplicationContext()
  • 使用AppWidgetManager 更新您的应用小部件实例,使用您在上一步中检索到的Intent 提取的电池电量(注意:如果您将它们全部设置为相同,则无需迭代在 ID 上 -- 使用以 ComponentName 作为参数的 updateAppWidget()

这有几个优点:

  1. 你不在乎ACTION_BATTERY_CHANGED 的广播频率
  2. 用户可以通过执行这些检查来控制您消耗多少电池(如果您将轮询时间保持在一分钟或更长时间,则应该可以忽略不计)
  3. 您的进程可以在两次轮询之间安全终止,从而减少用户使用任务杀手攻击您并半永久性地搞砸您的应用的可能性

【讨论】:

  • 这不是解决这个问题的最佳方式。我见过很多闭源电池小部件,一旦发生变化就会更新它们的信息(BattStatt 就是一个很好的例子)。我从未见过为用户提供更新间隔的产品。电池电量小部件应该始终准确。
  • @Nick:“这不是解决这个问题的最佳方式”——您有权发表自己的意见。 “我见过很多闭源电池小部件,它们会在发生变化时立即更新它们的信息”——它们通过一直将服务保存在内存中来浪费大量 RAM 来做到这一点。用户认为这样做的开发人员是白痴,为什么任务杀手如此受欢迎,操作系统必须主动杀死此类服务。
  • @Nick:“电池电量小部件应该始终准确”——由于电池电量不会特别频繁地变化,因此轮询架构可以足够准确,同时避免 RAM 命中和始终保持服务的固有不可靠性。
  • 好吧,你让我信服了。现在,您说要在“那个”BroadcastReceiver 中注册 ACTION_BATTERY_CHANGED。那会是我的 AppWidgetProvider 的 onReceive 函数吗?因为我试过了,它似乎根本没有注册。
  • @Nick:“那会是我的 AppWidgetProvider 的 onReceive 函数吗?” -- 不,它将在您设置的BroadcastReceiver 中接收来自AlarmManager 的警报。当根据您的轮询周期发生警报事件时,您可以通过registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 获取当时的电池电量。
【解决方案2】:

好吧,您的 onUpdate 正在将自己的类注册为电池信息意图的接收器。然后立即针对第一个信息触发此意图。 您的 onReceive 再次调用您的 onUpdate。我们称之为循环。因此每秒 100 条日志...

【讨论】:

    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 2021-01-21
    • 2011-01-06
    • 2011-01-27
    • 2018-05-04
    相关资源
    最近更新 更多