Статьи

Планирование фоновых задач в Android

Периодически вашему Android-приложению может потребоваться выполнить задачу, например, проверить сервер на наличие обновлений. Класс AlarmManager можно использовать для планирования и выполнения операций, которые должны выполняться, даже если приложение не запущено.

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

Тип тревоги и точность

Существует два основных типа будильника: истекшие часы реального времени и часы реального времени. Первое соответствует времени с момента загрузки системы, а второе — времени UTC. Различные типы сигналов тревоги могут быть установлены либо для пробуждения ЦП устройства в спящем режиме, либо для срабатывания при следующем пробуждении устройства. Ниже приведен список различных доступных вариантов типа тревоги.

  • ELAPSED_REALTIME — запускает ожидающее намерение по истечении указанного промежутка времени с момента загрузки устройства. Если устройство спит, оно срабатывает при следующем пробуждении устройства.

  • ELAPSED_REALTIME_WAKEUP — запускает ожидающее намерение по истечении указанного промежутка времени с момента загрузки устройства. Он будит устройство, если оно спит.

  • RTC — запускает ожидающее намерение в указанное время. Если устройство спит, оно не будет доставлено до следующего пробуждения устройства.

  • RTC_WAKEUP — запускает ожидающее намерение в указанное время, пробуждая устройство, если оно спит.

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

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

Настройка повторяющейся задачи

Мы создадим простое приложение, чтобы показать расписание задач. Задачей, которую мы наметим, будет отображение сообщения с помощью Toast ( Toast предоставляет простой отзыв об операции в небольшом всплывающем окне). Код для этого проекта можно найти на этом Git Repo .

Создайте новый проект Android. Для просмотра создайте две кнопки, которые будут запускать и останавливать периодические операции.

В res/layout/activity_main.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <Button android:id="@+id/button1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Start Alarm" android:onClick="startAlarm" /> <Button android:id="@+id/button2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Cancel Alarm" android:onClick="cancelAlarm" /> </LinearLayout> 

Чтобы получить намерения, мы настроим приемник вещания для выполнения операции при срабатывании тревоги. Создайте класс, который наследуется от BroadcastReceiver . В методе onReceive , который вызывается, когда BroadcastReceiver получает широковещательную onReceive Intent , мы onReceive код, который выполняет нашу задачу.

В AlarmReceiver.java

 package com.example.alarmexample; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context arg0, Intent arg1) { // For our recurring task, we'll just display a message Toast.makeText(arg0, "I'm running", Toast.LENGTH_SHORT).show(); } } 

Затем нам нужно зарегистрировать BroadcastReceiver в файле манифеста. AlarmReceiver в файле манифеста.

 <application> . . <receiver android:name=".AlarmReceiver"></receiver> . . </application> 

Чтобы запустить тревогу, мы startAlarm метод startAlarm объявленный в res/layout/activity_main.xml выше, как метод, запускаемый при нажатии кнопки Start Alarm.

В MainActivity.java объявите переменную PendingIntent и AlarmManager . PendingIntent будет использоваться для установки и отмены аварийных сигналов.

В MainActivity.java включают следующие переменные экземпляра.

 private PendingIntent pendingIntent; private AlarmManager manager; 

В onCreate() мы создаем Intent который ссылается на наш класс приемника вещания и использует его в нашем PendingIntent .

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Retrieve a PendingIntent that will perform a broadcast Intent alarmIntent = new Intent(this, AlarmReceiver.class); pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0); } 

Затем мы включаем метод, который будет устанавливать повторяющиеся сигналы тревоги. После установки будильник срабатывает каждые 10 секунд.

 public void startAlarm(View view) { manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); int interval = 10000; manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent); Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show(); } 

Запустите приложение и, нажав кнопку «Start Alarm», появится сообщение «Alarm Set», а затем сообщение «Я бегу» каждые 10 секунд.

Мы использовали метод setRepeating() для установки повторяющейся тревоги, но setInexactRepeating() также может быть использован. С помощью setInexactRepeating() повторяющиеся сигналы тревоги от нескольких приложений будут синхронизироваться и срабатывать одновременно. Это уменьшит количество раз, когда устройство просыпается, экономя заряд батареи. Начиная с Android 4.4 все повторяющиеся тревоги неточны.

Метод setRepeating() принимает четыре аргумента:

  1. typetype тревоги, определяемый единицами времени использования и должен ли он возникать, когда устройство находится в спящем режиме. Может быть ELAPSED_REALTIME , ELAPSED_REALTIME_WAKEUP , RTC или RTC_WAKEUP .

  2. triggerAtMillis — время в миллисекундах, в течение которого сигнализация должна срабатывать первой.

  3. intervalMillis — интервал в миллисекундах между последующими повторами тревоги.

  4. operation — действие, выполняемое при срабатывании будильника

Далее мы cancelAlarm() метод cancelAlarm() чтобы остановить аварийные сигналы. Включите метод ниже в MainActivity.java

 public void cancelAlarm(View view) { if (manager != null) { manager.cancel(pendingIntent); Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show(); } } 

Перед повторным запуском приложения выполните принудительную остановку или удалите приложение на устройстве или в симуляторе. Если вы этого не сделаете, предыдущий график тревоги все еще будет работать. Запустите приложение, и запланированный будильник может быть остановлен.

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

 Intent alarmIntent = new Intent(this, AlarmReceiver.class); pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0); manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); manager.cancel(pendingIntent); Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show(); 

Вывод

Мы рассмотрели, как AlarmManager можно использовать для планирования периодических задач. AlarmManager лучше всего использовать для задач, которые должны выполняться, даже если приложение не открыто. Для обычных операций синхронизации, которые должны выполняться во время использования приложения (тики, тайм-ауты и т. Д.), Более эффективно использовать методы обработчика postDelayed() и postAtTime() . AlarmManager требует слишком много накладных расходов, чтобы оправдать его использование таким образом.