На форуме (http://fire-monkey.ru/), не раз просили рассказать, как использовать AlarmManager в RAD Studio или как написать свой будильник :). В этой статье, я расскажу, как его использовать, примеров будет два. За основу взят пример «автозапуска приложения», однако в данной статье автозапуск будет происходить в назначенное время.
Update 23.02.17. Разъяснил различия между двумя вариантам из статьи.
Начнём с теории.
Теоретическое содержание:
1) AlarmManager
2) PendingIntent
AlarmManager
Официальная справка Google: http://developer.android.com/intl/ru/reference/android/app/AlarmManager.html
AlarmManager – это диспетчер оповещений или проще говоря, что-то вроде планировщика, который в назначенное время выполнит запланированное задание.
Методов у AlarmManager полно, я упомяну три основных (самых популярных), остальные вы найдёте в оф. справке.
Методы:
- set(int type, long triggerAtMillis, PendingIntent operation) – устанавливает разовое задание
- setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) – устанавливает повторяющееся задание
- cancel(PendingIntent operation) – отменяет задание
В качестве параметров, методы принимают:
- тип задания (int type)
- ELAPSED_REALTIME - ориентируются на время от начала загрузки ОС
- ELAPSED_REALTIME_WAKEUP - ориентируются на время от начала загрузки ОС и пробуждает устройство из сна.
- RTC - ориентируются на системное время
- RTC_WAKEUP - ориентируются на системное время и пробуждает устройство из сна.
- Время для запуска задания, указывается в миллисекундах.
- (setRepeating, long intervalMillis) Интервал в миллисекундах между повторами
- PendingIntent – Ожидающее намерение с заданием, которое мы хотим выполнить
Особенности:
- нельзя запланировать два одинаковых задания
- после перезагрузки/выключения устройства, все задания будут удалены
PendingIntent
Официальная справка Google: http://developer.android.com/intl/ru/reference/android/app/PendingIntent.html
Основные методы:
- getActivity –для запуска Activity
- getBroadcast – для BroadcastReciver
- getService – для Service
Параметры, принимаемые методами, на примере getBroadcast:
getBroadcast(
- mContext, - контекст, активность или служба
- 1, - идентификатор запроса, позволяет создавать похожие ожидающие намерения
- intent, - намерение
- 0); - флаги ожидающего намерения (флаги намерений полезны в управлении временем жизни ожидающего намерения. Однако в данном случае время жизни поддерживается диспетчером оповещений. Например, чтобы отменить ожидающее намерение, нужно запросить его отмену у диспетчера оповещений.)
На этом, краткий курс теории закончился. Давайте посмотрим, как же это всё использовать на деле.
Практика.
Как я говорил в самом начале, за основу взят пример автозапуска приложения.
Пример №1 – запускаем приложение, с помощью BroadcastReceiver и метода PendingIntent.getBroadcast
Пример №2 – запускаем приложение, используя только метод PendingIntent.getActivity
Update 23.02.17. Друзья, ниже в комментарии уведомили меня(?!), что непонятны различия между этими двумя вариантами.
Всё просто:
Приложение будем запускать через 30 секунд после установки задания.
Всё просто:
- Для первого примера мы используем метод getBroadcast, а значит нам обязательно нужен BroadcastReceiver, а значит, нужен java класс и файл classes.dex. Опять же, я всегда стараюсь описывать все действия подробно, но вы можете опустить часть с classes.dex и просто добавить JAR в Project Manager'е, подробности читайте тут Как добавить jar библиотеку в проект
- Для второго примера мы используем метод getActivity, поэтому нам не нужны BroadcastReceiver, JAVA class, JAR, classes.dex, manifest, т.е. достаточно просто написать код из второго примера и всё заработает.
Приложение будем запускать через 30 секунд после установки задания.
Общая функция для примеров:
function getTimeAfterInSecs(Seconds: Integer): Int64; var Calendar: JCalendar; begin Calendar := TJCalendar.JavaClass.getInstance; Calendar.add(TJCalendar.JavaClass.SECOND, Seconds); Result := Calendar.getTimeInMillis; end;
Данная функция возвращает время срабатывания в миллисекундах.
Пример №1
Создаём java-файл с классом «AlarmReceiver», генерим файл classes.dex. Как это сделать, я писал уже не один раз, например, почитайте последние статьи в блоге. Больше всего подойдёт статья «[BroadcastReceiver] Автозапуск приложения после перезагрузки ОС».
Update 23.02.17. Действительно для XE7 и выше. BAT - файл для JAVA 1.7 - 1.8
Для тех, кто уже понимает или наоборот не хочет понимать, для чего нужен classes.dex. Можете его не создавать.
Вы можете создать JAR файл с вашим JAVA классом и добавить его через Project Manager (Как добавить jar библиотеку в проект, в данном случае, обёртку делать не нужно).
Для создания JAR файла, вам необходимо использовать bat файл с таким содержимым:
После выполнения этого bat файла, у вас появится файл output\jar\test_classes.jar. Его то и добавьте через Project Manager (подробности в статье, указанной чуть выше).
Update 23.02.17. Действительно для XE7 и выше. BAT - файл для JAVA 1.7 - 1.8
Для тех, кто уже понимает или наоборот не хочет понимать, для чего нужен classes.dex. Можете его не создавать.
Вы можете создать JAR файл с вашим JAVA классом и добавить его через Project Manager (Как добавить jar библиотеку в проект, в данном случае, обёртку делать не нужно).
Для создания JAR файла, вам необходимо использовать bat файл с таким содержимым:
@echo off setlocal if x%ANDROID% == x set ANDROID=C:\Android\sdk set ANDROID_PLATFORM=%ANDROID%\platforms\android-24 set PROJ_DIR=%CD% set VERBOSE=0 echo. echo Compiling the Java service activity source files echo. mkdir output 2> nul mkdir output\classes 2> nul if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose javac -source 1.7 -target 1.7 %VERBOSE_FLAG% -Xlint:deprecation -cp %ANDROID_PLATFORM%\android.jar -d output\classes src\com\TestReceiver\BootCompletedReceiver.java echo. echo Creating jar containing the new classes echo. mkdir output\jar 2> nul if x%VERBOSE% == x1 SET VERBOSE_FLAG=v jar c%VERBOSE_FLAG%f output\jar\test_classes.jar -C output\classes com echo. echo Now we have the end result, which is output\jar\test_classes.jar :Exit pause endlocal
После выполнения этого bat файла, у вас появится файл output\jar\test_classes.jar. Его то и добавьте через Project Manager (подробности в статье, указанной чуть выше).
Код в java-файле:
package com.TestReceiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class AlarmReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Intent TestLauncher = new Intent(); TestLauncher.setClassName(context, "com.embarcadero.firemonkey.FMXNativeActivity"); TestLauncher.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(TestLauncher); } }
Создаём приложение, кидаем кнопку, подключаем необходимые для работы модули (юниты):
uses Androidapi.JNI.JavaTypes, Androidapi.JNI.App, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText;
пишем код в событии OnClick:
procedure TForm2.Button1Click(Sender: TObject); var Intent: JIntent; PendingIntent: JPendingIntent; begin // Создаём Интент Intent := TJIntent.Create; Intent.setClassName(TAndroidHelper.Context, StringToJString('com.TestReceiver.AlarmReceiver')); // Оборачиваем Интент в PendingIntent PendingIntent := TJPendingIntent.JavaClass.getBroadcast(TAndroidHelper.Context, 1, Intent, 0); // Устанавливаем оповещение TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30), PendingIntent); end;
Делаем сборку (Build) проекта, вносим правку в файл AndroidManifest.template.xml:
<receiver android:name="com.TestReceiver.AlarmReceiver" />
Заменяем стандартный classes.dex и теперь всё готово. Приложение, уже можно запустить, но можете сразу добавить в приложение второй пример :)
Пример №2
Этот пример независим от первого примера. Т.е. в этом примере вам НЕ нужно всё то, что мы делали в первом примере (BroadcastReceiver, JAVA class, JAR, classes.dex, manifest). Можно смело копировать код из этого примера и использовать в своём приложении, ничего другого не нужно делать.
Добавляем на форму вторую кнопку и пишем код:
Добавляем на форму вторую кнопку и пишем код:
procedure TForm2.Button2Click(Sender: TObject); var Intent: JIntent; PendingIntent: JPendingIntent; begin // Создаём Интент Intent := TJIntent.Create; Intent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity')); // Оборачиваем Интент в PendingIntent PendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 1, Intent, 0); // Устанавливаем оповещение TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30), PendingIntent); end;
Запускаем приложением и тестим.
Вот так, просто, можно использовать AlarmManager в RAD Studio.
Видео
Исходный код: Скачать с Google Drive