Содержание
- Проблемы с сервисами
- Планирование задач в жизненном цикле вашего приложения
- Планирование задач вне жизненного цикла вашего приложения
- Упражнение
- Заключение
При разработке современных приложений очень часто бывает так, что задачи в них выполняются асинхронно, и их объем выходит за рамки жизненного цикла приложения, например, загрузка различных данных или обновление сетевых ресурсов. В некоторых ситуациях нам также нужно сделать какую-то работу, но не обязательно сейчас. Чтобы запланировать фоновые работы, Android предоставляет несколько API, которые мы можем использовать с умом в наших приложениях.
Выбор подходящего планировщика может улучшить производительность приложения и время автономной работы устройства.
Начиная с Android M также используется режим Doze, чтобы свести к минимуму расход аккумулятора, когда пользователь некоторое время находится вдали от устройства.
Существует несколько API для планирования задач в Android:
- Менеджер системных сообщений (AlarmManager)
- Планировщик заданий (JobScheduler)
- Сетевой менеджер GCM
- Диспетчер заданий Firebase (Firebase JobDispatcher)
- Адаптер синхронизации (SyncAdapter)
- Библиотека Android-Job
Проблемы с сервисами
Сервисы позволяют выполнять длительные операции в фоновом режиме. Запуск сервисов в фоновом режиме очень затратен для батареи устройства.
Сервисы особенно вредны, когда они постоянно используют ресурсы устройства, даже если они не выполняют полезную работу. Проблема усугубляется, когда эти фоновые сервисы прослушивают различные системные широковещательные каналы (например, CONNECTIVITY_CHANGE или NEW_PICTURE и т.д.).
Планирование задач в жизненном цикле вашего приложения
Когда приложение запущено, и мы хотим запланировать или запустить задачу в определённое время, рекомендуется использовать класс Handler совместно с Timer и Thread. Вместо использования AlarmManager и других, это наиболее лёгкий и эффективный способ.
Планирование задач вне жизненного цикла вашего приложения
AlarmManager
AlarmManager обеспечивает доступ к службам установки задач на системном уровне. Это даёт возможность выполнять любые операции за пределами жизненного цикла вашего приложения. Таким образом, вы можете запускать события или действия, даже если ваше приложение не запущено. AlarmManager также может запускать сервис в будущем. Он используется для запуска PendingIntent, когда задача отключается.
Зарегистрированные задачи сохраняются, когда устройство спит (и при необходимости могут пробудить устройство, если оно отключится в течение этого времени), но очищаются, если оно выключено и перезагружено.
API AlarmManager нужно использовать только для задач, которые должны выполнять в определённое время. Он не обеспечивает более надёжные выполнения условий, таких как устройство в режиме ожидания, доступность сети или обнаружение заряда.
Пример использования: предположим, что мы хотим выполнить задачу через 1 час или через каждый час. В этом случае AlarmManager отлично работает. Но этот API не подходит в ситуации, описанной выше, тогда, когда сеть доступна или устройство не заряжается.
JobScheduler
Это главный из всех упомянутых вариантов планирования, поскольку очень эффективен для работы в фоне. JobScheduler API был представлен в Android 5.0 (API 21).
Этот API позволяет группировать задания, когда у устройства больше доступных ресурсов или при соблюдении правильных условий. Все условия могут быть определены при создании задания. Когда объявленные критерии будут достигнуты, система выполнить задание в JobScheduler вашего приложения. JobScheduler также отменяет выполнение, если необходимо, чтобы соблюдались ограничения режимов Doze и App Standby.
Группировка заданий таким образом позволяет устройству дольше сохранять время автономной работы. В общем, этот API можно использовать для планирования всего, что не критично для пользователя.
Сетевой менеджер GCM
Сетевой менеджер GCM (Google Cloud Messaging) имеет все функции планирования из JobScheduler. Он также предназначен для выполнения многократной или одноразовой работы при сохранении времени автономной работы.
Он используется для поддержки обратной совместимости и может также использоваться на версиях ниже Android 5.0 (API 21). Начиная с уровня API 23 и выше, сетевой менеджер GCM использует платформу JobScheduler. Он используется механизм планирования в сервисах Google Play, поэтому этот класс будет работать только в том случае, если на устройстве установлены сервисы Google Play.
Google настоятельно рекомендует пользователям GCM перейти на FCM и вместо этого использовать диспетчер задач Firebase для планирования любых задач.
Firebase JobDispatcher
Firebase JobDispatcher также является библиотекой для планирования фоновых задач. Он также используется для поддержки обратной совместимости (ниже API 21) и работает во всех последних версиях Android (начиная с API 9).
Эта библиотека также будет работать, если на устройстве нет установленных сервисов Google Play и вы хотите запланировать работу в приложении. В этом случае библиотека будет использовать AlarmManager. Если на устройстве доступны сервисы Google Play, то библиотека используется их в качестве механизма планирования.
Совет: Он использует AlarmManager для поддержки API <= 21, если сервисы Google Play недоступны.
Для устройства, работающего на уровне API 21, он использует JobScheduler. Эта библиотека также имеет ту же структуру, так что изменений в функциональности нет.
Адаптер синхронизации
Адаптеры синхронизации предназначены специально для синхронизации данных между устройством и облаком. Они должны использоваться только для этого типа задач. Синхронизация может быть вызвана изменениями данных в облаке или на устройстве, по истекшему времени или времени суток. Android попытается сгруппировать исходящие сигналы синхронизации, чтобы сэкономить время автономной работы. Система будет пытаться синхронизировать только тогда, когда устройство подключено к сети.
По возможности, через Google можно использовать JobScheduler, Firebase JobDispatcher или сетевой менеджер GCM.
В Android N (API 24) SyncManager находится поверх JobScheduler. Вы должны использовать только класс SyncAdapter, если вам требуются дополнительные функции, которые он предоставляет.
Библиотека Android-Job
Данная библиотека, аналогичным предыдущим нативным решениями, позволяет выполнять задачи в фоновом процессе. Однако главной её особенностью является то, что она сама решает, какой API лучше всего подходит для вашей задачи, поскольку включает в себя все возможности AlarmManager, JobScheduler и GcmNetworkManager.
Настройка библиотеки проста, для этого достаточно инициализировать JobManager, а затем можно приступать к планированию своих задач. Нет необходимости объявлять какие-либо службы, слушатели и разрешения в манифесте.
Чтобы установить библиотеку, достаточно добавить в файле Gradle следующую зависимость:
dependencies {
compile 'com.evernote:android-job:1.1.11'
}
Подробнее о библиотеке и её методах можно прочитать здесь.
Упражнение
Мы обсудили множество теоретических вопросов, поэтому теперь посмотрим, как использовать планировщик заданий для Android.
- Создайте JobService
Создайте JobSchedulerService и наследуйте класс JobService, который требует создания двух методов onStartJob(JobParameters params) и onStopJob(JobParameters params).
public class JobSchedulerService extends JobService { @Override public boolean onStartJob(JobParameters params) { return false; } @Override public boolean onStopJob(JobParameters params) { return false; } }
Метод onStartJob(JobParameters params) вызывается, когда JobScheduler решает запустить вашу задачу. JobService работает в основном потоке, поэтому любая логика должна выполняться в отдельном потоке. Метод onStopJob(JonParameters params) вызывается, если система решила, что вы должны прекратить выполнение своей задачи ещё до того, как у вас будет возможность вызвать jobFinished(JobParameters, boolean).
Вам также необходимо зарегистрировать свой сервис задач в AndroidManifest.
<application> <service android:name=”.JobSchedulerService “ android:permission=”android.permission.BIND_JOB_SERVICE” android:exported=”true”/> </application>
- Создайте объект JobInfo
Чтобы создать объект JobInfo, передайте JobService в JobInfo.Builder(), как показано ниже. Этот конструктор задач позволяет установить множество различных параметров управления при выполнении задачи.
ComponentName serviceName = new ComponentName(context, JobSchedulerService.class);
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceName) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build();
- Спланируйте задачу
Теперь у нас есть JobInfo и JobService, поэтому пришло время планировать нашу задачу. Всё, что нам нужно сделать, это запланировать задачу с требуемой JobInfo, как показано ниже:
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); int result = scheduler.schedule(jobInfo); if (result == JobScheduler.RESULT_SUCCESS) { Log.d(TAG, “Задача успешно запланирована!”); }
Заключение
При планировании задачи вам нужно тщательно подумать о том, когда и что должно запускать вашу задачу, и что должно произойти, если она по какой-то причине не сработает. Вы должны быть очень осторожны с производительностью вашего приложения, а также с другими аспектами, такими как срок службы батареи.
JobScheduler легко реализует и обрабатывает большую часть сложностей для вас. При использовании JobScheduler наши запланированные задачи сохраняются, даже если система перезагружается. В настоящий момент единственный недостатком JobScheduler является то, что он доступен только для API 21 и выше.