ACTION_BATTERY_CHANGED стреляет как сумасшедший

Итак, я работаю над 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 вызовов журнала в секунду, говоря, что получает ACTION_BATTERY_CHANGED. Разве это не должно быть транслировано только на каждый процент снижения? Это фактически вызвало зависание всего моего модуля запуска, мне пришлось удалить его. Это не может быть правдой.

2 ответа

Решение

Мой код выглядит так:

Вы не можете зарегистрировать BroadcastReceiver От другого BroadcastReceiver и получить достоверные результаты. Android остановит ваш процесс, потому что он не думает, что что-то работает. Единственный способ слушать ACTION_BATTERY_CHANGED будет зарегистрировать этого получателя от деятельности или службы.

Разве это не должно быть транслировано только на каждый процент снижения?

Где вы видите это документально? НАСКОЛЬКО МНЕ ИЗВЕСТНО, ACTION_BATTERY_CHANGED будет транслироваться всякий раз, когда оборудование чувствует, как это. Кроме того, имейте в виду, что другие данные изменяются в пределах этого Intent, такие как температура.

Если вы хотите реализовать этот виджет приложения, не регистрируйтесь на ACTION_BATTERY_CHANGED таким, какой ты есть. Вместо:

  • Разрешить пользователю выбирать период опроса через SharedPreference (например, раз в минуту, раз в 15 минут)
  • использование AlarmManager чтобы дать вам контроль над этим периодом опроса с помощью getBroadcast()PendingIntent
  • В этом BroadcastReceiver, вызов registerReceiver() за ACTION_BATTERY_CHANGED но с null BroadcastReceiver, так как это вернет вам последний Intent который транслировался для этого действия (примечание: вам все равно нужно будет использовать getApplicationContext() за это)
  • использование AppWidgetManager обновить экземпляры виджета вашего приложения с уровнем заряда батареи, извлеченной из Intent Вы получили на предыдущем шаге (примечание: если вы устанавливаете их все одинаковыми, вам не нужно перебирать идентификаторы - используйте updateAppWidget() это занимает ComponentName как параметр)

Это имеет несколько преимуществ:

  1. Вам все равно, как часто ACTION_BATTERY_CHANGED транслируется
  2. С помощью этих проверок пользователь получает возможность контролировать, сколько батареи вы потребляете (должно быть незначительным, если вы держите период опроса до минуты или более)
  3. Ваш процесс может быть безопасно остановлен между опросами, что снижает вероятность того, что пользователи будут атаковать вас убийцами задач и наполовину навредить вашему приложению

Ну, ваш onUpdate регистрирует свой собственный класс в качестве получателя для намерения batteryinfo. Это намерение тогда немедленно вызвано для первой информации. Ваш onReceive снова вызывает ваш onUpdate. Мы называем это петлей. Следовательно 100 журналов в секунду...

Другие вопросы по тегам