Статьи

Приложения AlarmManager и Sleepy для Android

В моей первой статье, объясняющей, как кодировать виджет Android , мы рассмотрели шаги, необходимые для создания базового виджета, который обновляется не часто и использует стандартные компоненты. Однако мы не могли заставить его регулярно обновлять виджет.

В этой статье я покажу вам, как периодически добавлять обновления в ваш виджет с помощью AlarmManager. Я полагаю, что вы уже прочитали вводную статью о кодировании виджетов Android или знаете основы программирования в виджетах приложений .

Часто обновляемые виджеты

Android-виджеты обновляют свое содержимое по расписанию, что приводит к пробуждению телефона, даже если экран выключен. Если частота обновления установлена ​​слишком высоко, это может привести к чрезмерному использованию батареи. В результате система Android ограничивает частоту обновления виджетов раз в полчаса или более.

Это бесполезно, если вы хотите часто обновляемый виджет, например часы. Здесь нам нужен метод частого обновления виджета при включенном экране и только при включенном экране. К счастью, есть способ сделать это, используя « AlarmManager », который является системной службой, в которой ваш код регистрирует события, которые должны происходить в определенное время или в определенные периоды. Это позволяет что-то происходить в определенное время, даже если приложение не работает в это время. Еще лучше, если вы укажете правильный тип таймера, вы можете запретить ему доставлять событие, если телефон спит во время его выключения. Это делает его идеальным для нашего дела.

Как и в случае обновлений виджетов, тревоги доставляются в виде Intents , как и все в Android. Итак, первое, что нам нужно сделать, это настроить наше приложение для прослушивания пользовательского типа намерения, который мы будем создавать специально для наших обновлений часов.

Откройте AndroidManifest.xml и добавьте новый intent-filter под существующим фильтром для APPWIDGET_UPDATE. Поскольку мы используем собственное намерение, мы получаем его имя сами, но оно должно быть полностью квалифицированным (то есть иметь обратное доменное имя спереди), чтобы мы могли различать наши намерения и всех остальных в системе. В этом случае я выбрал com.eightbitcloud.example.widget.8BITCLOCK_WIDGET_UPDATE в качестве имени.

 <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <intent-filter> <action android:name="com.eightbitcloud.example.widget.8BITCLOCK_WIDGET_UPDATE" /> </intent-filter> 

Затем нам нужно написать некоторый код в нашем «ProviderHandler», чтобы настроить «AlarmManager» для регулярной отправки наших намерений. Загрузите «WidgetProvider», который мы создали в первом уроке, и добавьте следующие методы:

 private PendingIntent createClockTickIntent(Context context) { Intent intent = new Intent(CLOCK_WIDGET_UPDATE); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); return pendingIntent; } @Override public void onEnabled(Context context) { super.onEnabled(context); Log.d(LOG_TAG, "Widget Provider enabled. Starting timer to update widget every second"); AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.A LARM_SERVICE); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.add(Calendar.SECOND, 1); alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 1000 , createClockTickIntent(context)); } @Override public void onDisabled(Context context) { super.onDisabled(context); Log.d(LOG_TAG, "Widget Provider disabled. Turning off timer"); AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(createClockTickIntent(context)); } 

onEnabled() и onDisabled() вызываются соответственно, когда создается первый виджет вашего типа, а последний удаляется. Мы хотим начать рассылать обычные тики при создании первого виджета, и мы хотим остановить «AlarmManager», когда последний виджет удален. Мы просто вызываем AlarmManager.setRepeating() чтобы создать повторяющуюся тревогу, а затем вызываем cancel() когда мы закончим с ним.

Обратите внимание, что когда мы создаем сигнал тревоги, мы указываем тип AlarmManager.RTC тревоги AlarmManager.RTC . Этот тип тревоги генерируется только тогда, когда телефон не спит. Это функция, на которую мы полагаемся, чтобы доставлять обновления только тогда, когда устройство находится в активном состоянии, а не когда устройство спит.

Теперь мы сказали Android, что наше приложение заинтересовано в получении этих намерений, и мы настроили «AlarmManager» для отправки намерений на регулярной основе. Осталось только написать код, который будет обрабатывать намерения, когда они появятся. Измените свой класс ‘ WidgetProvider ‘, чтобы включить следующий код:

 /** * Custom Intent name that is used by the 'AlarmManager' to tell us to update the clock once per second. */ public static String CLOCK_WIDGET_UPDATE = "com.eightbitcloud.example.widget.8BITCLOCK_WIDGET_UPDATE"; @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); Log.d(LOG_TAG, "Received intent " + intent); if (CLOCK_WIDGET_UPDATE.equals(intent.getAction())) { Log.d(LOG_TAG, "Clock update"); // Get the widget manager and ids for this widget provider, then call the shared // clock update method. ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName()); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget); for (int appWidgetID: ids) { updateAppWidget(context, appWidgetManager, appWidgetID); } } } 

Этот код прослушивает намерение и обновляет содержимое компонента при получении. Фактический код для обновления виджета такой же, как и в предыдущей статье, но он был преобразован в метод updateAppWidget чтобы избежать повторения. Посмотрите полный код класса для получения дополнительной информации.

Так что у вас есть это. Используя «AlarmManager», мы можем заставить операционную систему Android отправлять наше приложение на регулярной основе. В этом примере мы использовали технику для обновления виджета очень часто, но его также можно использовать для периодического обновления других компонентов в вашем приложении. В качестве примера я часто вижу, что у людей есть фоновые службы, которые периодически обновляют свои сетевые каналы. Это работает, но служба постоянно работает, занимая память на устройстве. Если бы они использовали «AlarmManager», они могли бы просто активировать свой сервис каждый раз, когда ему нужно было сделать обновление.

Я надеюсь, что эта статья показала, как просто использовать AlarmManager. Как всегда, код доступен на GitHub на примере виджета . В следующей статье мы рассмотрим, как представить сложные компоненты пользовательского интерфейса в виджетах.