Планировщик запуска программ по расписанию для андроид
Современный смартфон умеет очень многое из того, что казалось невозможным еще каких-то лет десять назад. Приложение Tasker может сделать его во много раз умнее и превратить в настоящее устройство будущего
- Основная терминология
- Начало работы
- Запуск задач при помощи виджета в ручном режиме
- Включение функций энергосбережения при низком заряде аккумулятора
- Звуковой сигнал в случае перегрева аккумулятора
- Отправка уведомлений на основе местоположения
- Автоматический ответ на SMS и пропущенные звонки
- Включение беззвучного режима при переворачивании смартфона экраном вниз
- Заключение
В середине лета число приложений в официальном магазине Google Play достигло одного миллиона. И, возможно, самое функциональное среди них — это Tasker. Несмотря на то, что приложение не относится к категории «Игры», несмотря на то, что оно требует немало времени на освоение, все же оно стабильно держится в топе самых популярных платных программ в Google Play.
В том, что у Tasker огромная аудитория почитателей, нет ничего удивительного, ведь приложение дает возможность каждому найти свои способы его использования. Если говорить в общем, Tasker — это приложение для автоматизации. В его основе лежит идея о том, что многие действия, которые пользователь выполняет на своем мобильном устройстве, являются, во-первых, повторяемыми, а во-вторых, связанными с некими событиями. Например, когда вы приходите в театр или в медицинский центр, вы отключаете звук на телефоне, а когда оказываетесь дома — включаете на планшете Wi-Fi. Все подобные действия Tasker может выполнять в автоматическом режиме, разгружая голову владельца мобильного устройства для других, более важных дел.
Tasker — не единственное приложение для автоматизации устройств с Android, и многие его возможности можно также обнаружить в программах on, Locale и им подобных. Однако других столь функциональных приложений, как Tasker, не существует. Программа выходит далеко за рамки обычных шаблонов — имея некоторые навыки ее использования, можно придумывать практически любые сценарии для автоматизации, содержащие множество уровней, и даже создавать на основе Tasker собственные приложения.
Но впервые загрузив Tasker (на сайте разработчика доступна бесплатная триал-версия, работающая в течение семи дней), вы, скорее всего, будете разочарованы. Приложение напоминает коробку с конструктором, в которой есть множество самых разных деталей. При этом не все детали подходят друг к другу, а никаких готовых сценариев использования в приложении нет.
Поэтому даже для того, чтобы создать самую простую цепочку действий, нужно предварительно разобраться с терминологией Tasker и принципами его работы.
Для работы с приложением используется семь основных терминов: задачи, действия, контексты, профили, проекты, сцены, переменные. В основе любых операций, которые способна выполнить программа, лежит формула: «Если произошло событие X, нужно автоматически выполнить Y».
Y в этой формуле — это действие, то, что приложение автоматически выполняет при определенных условиях. Действием может быть отправка SMS, отключение сигнала при поступлении входящих звонков, вывод на экран уведомления и так далее. Всего в приложении предлагается более двухсот действий. Большинство из них имеют настройки и могут быть связаны между собой.
X в формуле — это контекст, то есть некое событие или условие, при срабатывании которого Tasker начинает действовать. В приложении предусмотрено несколько видов контекстов: время, дата, место, событие и состояние.
Если смартфон оказался за чертой города, это контекст места, а 7:15 утра — контекст времени. Контекст события — это, например, поступление входящего звонка с указанного номера. А контекст состояния — это некое условие, которое является активным в течение некоторого промежутка времени. И в течение этого времени выполняются заданные действия.
Ни действия, ни контексты не существуют сами по себе. Действиями управляют задачи, а контекстами — профили. Одна задача может содержать любое количество действий, а один профиль — до четырех контекстов и до двух задач. Таким образом, в рамках одной операции можно выполнять целый набор действий.
Задачи могут содержать любое количество действий и даже быть многоуровневыми. В Tasker предусмотрено действие, запускающее задачу. Поэтому можно создать задачу, в состав которой будет входить действие, запускающее другую задачу. Задачи могут быть запущены в рамках профиля, а также сами по себе, например с помощью виджетов или ярлыков, через сторонние приложения.
Профиль включает и контексты, и задачи, причем если в профиле используется несколько контекстов, то только один из них может быть контекстом события, ведь одновременное срабатывание двух контекстов в то же самое время невозможно. Профиль имеет собственные настройки, при помощи которых можно выбирать приоритет запуска задач, включать «тихий» режим работы (когда информация о срабатывании профиля не видна в строке состояния Android), указывать максимальное число его срабатываний и выбирать минимально допустимый промежуток времени, который может проходить между двумя его запусками.
Также в Tasker предусмотрена возможность создания элементов пользовательского интерфейса, которые тут называются сценами. Понятие проекта используется для организации всех задач, профилей и сцен в одном месте, для экспорта и создания на основе настроек Taskler отдельных приложений.
Первое, что стоит сделать после запуска Tasker, — переключиться в обычный режим в настройках приложения. По умолчанию оно запускается в режиме новичка и имеет упрощенный интерфейс. На соответствующих вкладках можно создавать профили, задачи, сцены и просматривать список уже имеющихся.
Оранжевый значок в виде молнии в верхней части окна предназначен для быстрого включения/отключения всех активных профилей. Встроенный поиск можно использовать для обнаружения созданных ранее задач, профилей, сцен, настроек приложения, а также для получения справочной информации по программе (последняя возможность работает только в режиме онлайн).
Для примера создадим простой профиль, который будет автоматически запускать приложение Skype при подключении гарнитуры к устройству. На вкладке профилей нажмите на кнопку создания нового элемента приложения и выберите контекст состояния «Аппаратура → Наушники подключены». В списке «Тип» выберите вариант «С микрофоном», чтобы приложение реагировало только на подключение гарнитуры.
Вернитесь к списку профилей и добавьте в профиль новую задачу.
Нужно будет придумать для нее произвольное название, скажем «Запуск Skype». Добавьте в задачу новое действие. Для удобства организации они разделены по группам, которых более двадцати.
Перейдите в категорию «Сигнал → Menu». Теперь нужно настроить действие. Для этого в поле Items нажмите на кнопку добавления нового элемента, после чего щелкните по кнопке «Действие». Укажите категорию «Приложение → Запустить приложение», а затем выберите Skype в списке всех установленных приложений, который будет выведен на экран.
Новый профиль готов к использованию. По умолчанию все вновь создаваемые в Tasker профили включаются сразу же после создания, поэтому, если вы пока что не планируете работать с ним, воспользуйтесь переключателем напротив названия профиля.
Все задачи, созданные пользователем, сохраняются на вкладке Tasks. Их можно редактировать, а также использовать повторно при создании новых профилей. Список доступных задач показывается каждый раз при добавлении задачи в новый профиль. Кстати, если в списке случайно выбрана не та задача, можно быстро вернуться к окну выбора при помощи кнопки Switch Event. Подобная кнопка — Switch State — отображается и при добавлении контекста.
Если нужно, чтобы профиль содержал несколько контекстов или задач, достаточно коснуться уже имеющегося в нем контекста (задачи) и некоторое время удерживать палец. Появится меню, в котором можно выбрать добавление нового элемента. Это меню также дает возможность удалять текущие элементы, клонировать контексты (это удобно, если нужно добавить два однотипных контекста с немного измененными настройками), менять задачи на другие.
Как уже было сказано выше, задачи могут запускаться не только автоматически, в рамках профилей, но и по требованию пользователя. Один из удобных способов ручного запуска — создание виджета задачи на стартовом экране. В этом случае для запуска задачи соблюдения никаких условий не потребуется.
Чтобы создать виджет для запуска задачи, перейдите к списку виджетов Android. Коснитесь элемента Tasker и удерживайте палец, пока виджет не будет перенесен на стартовый экран. При этом возникнет меню выбора задачи. Можно будет или выбрать из уже имеющихся, или создать новую задачу. После этого Tasker предложит вам возможность добавить в задачу дополнительные действия и выбрать значок для показа виджета. После завершения настройки его можно будет увидеть на стартовом экране.
Несмотря на то, что в Tasker предусмотрена возможность ручного запуска, все же основное предназначение приложения — выполнение задач в автоматическом режиме. Поэтому рассмотрим примеры создания нескольких востребованных профилей.
Некоторые функции смартфонов удобны, но сильно влияют на время автономной работы устройства. Если нет возможности подзарядить смартфон и нужно, чтобы он проработал как можно дольше, при помощи Tasker можно настроить автоматическое отключение некоторых функций. Для этого используются контекст состояния и задача, содержащая несколько действий.
Добавьте контекст «Состояние → Зарядка → Уровень зарядки аккумулятора». В его настройках укажите уровень заряда, при котором задача будет срабатывать.
Создайте новую задачу и добавьте действие «Экран → Яркость дисплея». Уменьшите яркость дисплея до желаемого уровня. Вернитесь к добавлению действий и добавьте еще одно, например «Сеть → Изменить статус Wi-Fi». Убедитесь, что в настройках действия выбран вариант «Отключить». Теперь Tasker также будет отключать соединение по Wi-Fi.
Также можно отключить автосинхронизацию. Для этого добавьте действие «Сеть → Автосинхронизация» и выберите вариант «Выключить» в списке «Установка».
Можно добавить и другие действия, которые помогут продлить срок автономной работы устройства.
Перегрев аккумулятора может стать причиной выхода устройства из строя, поэтому неплохо было бы узнавать об этом как можно раньше, чтобы адекватно реагировать. Для создания такого профиля используется событийный контекст «Зарядка → Перегрев аккумулятора». Используемая в профиле задача будет включать действие «Сигнал → Уведомление со звуком».
Настройка действия сводится к выбору звукового файла (это может быть любой аудиофайл, хранящийся в памяти устройства или на SD-карте, а также сигнал из коллекции звуков Tasker). Также можно настроить вывод текстового уведомления на экране устройства. Текст нужно ввести в поле «Название».
Если устройство оснащено модулем GPS, можно использовать контекст «Место». Он очень полезен для забывчивых. Например, если вы все время забываете зайти в банк, чтобы забрать новую карточку, можно настроить Tasker таким образом, чтобы он прислал вам SMS, как только вы окажетесь в радиусе пятисот метров от отделения.
Контекст «Место» может работать и без GPS, с использованием сетевых настроек. Но определение местоположения в этом случае происходит менее точно.
При помощи Tasker можно настроить смартфон таким образом, что он автоматически будет переходить в беззвучный режим в заданное время, а потом возвращаться в обычный режим. Но ситуации, в которых громкий вызов телефона нежелателен, могут возникать и спонтанно. Предусмотреть их все невозможно, поэтому лучше запастись профилем, который будет отключать звонок при срабатывании простого условия: устройство перевернуто экраном вниз.
Для создания такого профиля добавьте контекст «Состояние → Sensor → Ориентация». В его настройках раскройте список «Положение» и выберите вариант «Экраном вниз».
Создайте новую задачу с действием «Аудио → Режим тишины». В настройках действия выберите вариант «Тишина» в списке «Режим».
Мы рассмотрели лишь несколько самых простых примеров работы с Tasker. Но программу можно с успехом использовать и в сотнях других случаев. Она может запускать приложения в заданное время, выводить на экран музыкальный плеер, как только вы вставляете наушники в гнездо, поздравлять с днем рождения всех друзей и родственников, автоматически отправляя SMS в нужные дни, будить любимых романтической эсэмэской по утрам и делать еще сотни других вещей, которые обязательно придут вам в голову, как только вы начнете использовать Tasker. Удачи в освоении!
AppAlarm
версия: 1.2.7 Pro
Последнее обновление программы в шапке: 07.02.2015
Краткое описание:
Запуск и остановка приложений по расписанию.
- Множество одновременных заданий
- Работа с любыми приложениями
- Возможность создавать ярлыки или указывать в качестве цели ярлыки с домашнего экрана
- Launch custom “AnyCut” style intents я не знаю, как перевести не коряво, чтобы все поняли
- Проигрывание сигнала при запуске приложения
- Выбор конкретной радиостанции Pandora для прослушивания
- Экспериментальная поддержка Google Listen (что это, смотреть тут)
- Возможность принудительного закрытия приложения после срабатывания
- Резервное копирование и восстановление настроек ваших будильников на/c SD карты
- Настройки повторяющихся событий
- Возможность запуска даже в момент разговора
- Проверка сети и возможность играть музыку из резервной копии, если нет подключения
- Включение/выключение Wi-Fi
- Настройки тайм-аута Wi-Fi
- Свои тайм-ауты
- Возможность установить предварительно громкость медиа.
Внимание: На Android 2.2 AppAlarm больше не может закрывать другие приложения. Обходной путь (чтобы убедиться, что музыка заиграет, когда AppAlarm сработает), это всегда выходить из Pandora или Slacker (или любого другого музыкального приложения, которое вы запускаете с помощью AppAlarm), когда вы закончите работу с ним. AppAlarm должен нормально работать на Android 2.1 и ниже.
Немного тестил на Defy (не во всех режимах), но то, что тестил, работает :)
Программа очень интересная
т.к. в памяти висит много процессов это сказывается на батарее а так можно по расписанию загружать программы и после выполнения (обновление погоды, смена профилей и т.п.) завершать ее. Вот еще бы перевод на русский :sveta:
А мне вот интересно, сможет ли она вырубить читалку (Moon+) через определенный промежуток времени (или в точное время)? Люблю перед сном почитать, под чтение и засыпаю, а читалка съедает заряд за ночь.
Приложение Kanbani представляет собой продвинутый планировщик задач, совмещающий в себе немалое количество функций, полезных не только деловым людям, но и тем, кто просто желает расходовать время с толком.
В отличие от большинства аналогов, это приложение может работать без интернета, в офлайн-режиме.
Интерфейс оформлен как доска с карточками. Это наглядно демонстрирует иерархию задач, приятно выглядит и удобно для пользователя. Доски можно объединять и разделять по каким-нибудь категориям. Однако из-за количества функций на изучение всех возможностей приложения требуется время. Для помощи в этом деле есть очень подробная справка, буквально по каждой кнопке.
Записи, кроме прочего, можно синхронизировать с сервером, чтобы работать над доской совместно с другими людьми или не потерять к ним доступ даже в случае утери смартфона. При этом все данные шифруются, исключая возможность доступа посторонних людей. Отсутствуют и какие-либо зависимости от сторонних сервисов, усиленные возможностью настроить свой сервер (SSH/SFTP, Apache mod_dav, OwnCloud).
Вместо канбан-досок можно включить режим календаря, если кому-то так привычнее.
Ещё в Kanbani нет ограничений на типы данных. Карточками, досками, текстами в описаниях — всем разрешено пользоваться в таком объёме, в каком это нужно. А с помощью команд, действующих сразу на несколько карточек, удобно управлять даже очень большими списками.
В общем, для деловых людей Kanbani может стать очень полезным и мощным инструментом в планировании рабочего и личного времени. Даже начинающие программисты смогут с лёгкостью читать и изменять его данные в виде JSON. А для всех остальных приложение станет удобным органайзером с ультимативной синхронизацией. Вдобавок оно полностью бесплатное, в нём нет ни рекламы, ни покупок.
ПЛАТФОРМА Android РУССКИЙ ИНТЕРФЕЙС да ТРЕБОВАНИЯ Android 4.4 или выше КАТЕГОРИЯ работа ЦЕНА бесплатно
Иногда при разработке под OS Android возникает необходимость выполнять ресурсоемкие операции периодически, регулярно или по запросу, и для этих операций важно, например, наличие интернета или чтобы устройство "не спало". Чаще всего при решении подобных задач применяются AlarmManager, WakefulBroadcastReceiver, либо же вообще WakeLock контролируется вручную. Все это не рекомендуется в документации для разработчиков под Android, а WakefulBroadcastReceiver уже отмечен как deprecated с API level 26.0.0.
Что же мы можем сделать, чтобы следовать рекомендациям Google и создавать приложения с более гибким поведением на версиях Android 5.0+, в которых энергосбережению уделяется все больше внимания? Если вы готовы выставить минимальный API level 21.0.0 для своего приложения, предлагаю под катом пример использования JobScheduler в связке с IntentService для последовательного выполнения трудоемких задач.
Суть вопроса и поднятых проблем
Достаточно открыть документацию по классу WakefulBroadcastReceiver, чтобы увидеть интересную ситуацию: класс добавлен в 22.0.0 версии API, а отмечен как deprecated в 26.0.0 версии. Можно предположить, что сначала разработчики Android решили добавить удобный класс для выполнения задач с удержанием WakeLock, но потом оказалось, что никто не гарантирует, что приложение будет работать на переднем плане, да и вообще когда каждое "умное" приложение пытается удержать WakeLock, когда же устройству экономить энергию? Да и принцип работы WakefulBroadcastReceiver стал идти в разрез со стремлением продлить время жизни заряда батареи, ведь кроме всего прочего незакрытый правильным образом ресивер мог привести к утечкам WakeLock'ов.
С другой стороны у рядовых разработчиков может возникнуть вопрос, как при всех новых ограничениях безопасно выполнять периодические задачи, когда, например, активен Doze mode? Чтобы уравновесить баланс ограничений и возможностей был создан JobScheduler, который берет на себя решение вопросов о том, когда задаче можно выполниться, каким приемлемым образом предоставить ей возможность выполнения, если это действительно очень нужно, и как при этом не нарушить политику энергосбережения и не потерять где-нибудь не отпущенный WakeLock.
Пока готовилась данная статья, на Хабре появилась статья другого автора, в которой раскрыто чуть больше теории и уделено чуть меньше внимания практике. Она будет полезной для быстрого старта и более глубоко понимания существующих альтернатив JobScheduler'у.
Пример создания проекта с JobScheduler и IntentService
Для простоты примера представим, что у нас есть задача по записи слова "Exercise" в файл, при этом нам нужен интернет, причем желательно не мобильный, потому что наша задача не стоит траты мобильного трафика пользователя. При этом мы хотим, чтобы каждая новая задача по записи слова выполнялась друг за другом. Так как нам нельзя блокировать главный поток (тут и работа с файлами и, возможно, какие-то сетевые запросы), и у нас задачи могут выстраиваться в очередь, на помощь нам приходит IntentService.
Для полного воспроизведения шагов, описанных в данной статье, необходимо создать новый проект без активити, с минимальной версией SDK 21. Также все действия можно производить в уже существующем проекте с минимальной версией SDK не ниже 21.
Добавление IntentService для обработки задач в фоне
Добавляем в проект новый IntentService, называем его ExerciseIntentService, используем стандартный подход, основанный на автоматически сгенерированных методах, почистив лишнее и переименовав методы и константы под наши условия.
В результате несложных манипуляций получаем следующее тело для ExerciseIntentService:
И так, сервис, который будет непосредственно выполнять наши однотипные условно-трудоемкие задачи по порядку, готов. Для того, чтобы создавать и планировать задачи, необходима точка входа, в качестве которой можно использовать BroadcastReceiver.
Добавление BroadcastReceiver для инициализации задач
Добавим в проект стандартными средствами BroadcastReciever и назовем его ExerciseRequestsReceiver. В дальнейшем мы сможем откуда угодно отправлять бродкасты нашему приложению, чтобы оно планировало выполнение задач (например, это можно сделать с помощью инструментальных тестов, что будет показано ближе к концу статьи).
Минимально необходимый код ExerciseRequestsReceiver выглядит так:
String ACTION_PERFORM_EXERCISE — действие для идентификации необходимости запуска процесса планирования задачи.
int sJobId — переменная для идентификатора задачи, который будет использован при планировании задач.
scheduleJob(context) — вызов метода, который будет содержать всю необходимую логику для планирования задачи.
Кстати, при использовании JobScheduler не нужно разрешение на WakeLock, в отличие от других способов решения подобной задачи.
Реализация наследника JobService для обработки событий от JobScheduler
JobScheduler требует отдельный сервис, унаследованный от JobService. Назовем его ExerciseJobService и добавим как обычный сервис, заменив родительский класс и добавив разрешение в манифест модуля:
Разрешение android.permission.BIND_JOB_SERVICE необходимо, чтобы данный сервис смог взаимодействовать с JobScheduler.
Кроме этого обязательными для реализации являются два метода onStartJob() и onStopJob() .
- onStartJob() вызывается когда настает время (условия) для выполнения запланированной задачи. Этот метод вызывается в главном потоке и любые тяжелые операции разработчик должен самостоятельно выносить в отдельные потоки (в нашем случае это уже предусмотрено — мы используем IntentService). При делегации выполнения задачи в другие потоки из onStartJob() необходимо вернуть true, а если все необходимые действия уже выполнены в теле этого метода, то вернуть нужно false.
- onStopJob() вызывается тогда, когда требуемые условия для задачи перестали выполняться либо отведенное для задачи время исчерпано. Вызов этого метода информирует сервис, что все фоновые задачи немедленно должны перестать выполняться. Лучше всего предусмотреть безопасную логику остановки выполнения для обеспечения целостности данных.
Для правильной обработки ситуации с onStopJob() можно реализовать статические флаги, какие-либо дополнительные бродкасты, а также можно использовать другие средства взаимодействия сервисов. В текущей статье это будет опущено и введено допущение, что если наш IntentService не смог выполнить задачу, то ничего страшного для логики приложения и целостности данных не произойдет.
onStopJob также имеет возвращаемое значение, если это true — то JobScheduler поставит прерванную задачу в очередь выполнения снова, false — задача будет считаться выполненной и будет удалена из очереди, если она не была периодической.
Так как обработка внештатных ситуаций опускается, вернем из этого метода true, чтобы задача перезапланировалась, заодно это нам позволит рассмотреть использование критерия повтора.
Таким образом, установив возвращаемые значения из двух основных методов и добавив запуск нашего ExerciseIntentService в onStartJob() , получаем следующий достаточно емкий сервис:
На данный момент уже подготовлен минимальный набор классов для реализации выполнения задачи через JobScheduler в IntentService, а именно: ExerciseIntentService — выполняет непосредственно необходимые для задачи операции в отдельных потоках, ExerciseJobService — ловит события от JobScheduler'a и запускает ExerciseIntentService, а ExerciseRequestsReceiver — входная точка для работы нашего комплекса, где мы ловим бродкасты извне и должны инициализировать задачу для JobScheduler, чем далее и займемся.
Создание новой задачи для JobScheduler
Для создания задачи для JobScheduler понадобится JobInfo.Builder. Его конструктор принимает два параметра: идентификатор задачи и ComponentName нашего ExerciseJobService.
Идентификатор задачи и ComponentName
С идентификатором все просто (но не без нюансов) — любое целочисленное значение:
- постоянное, если мы хотим обновлять уже запланированную задачу либо же контролировать единственность периодической задачи;
- уникальное значение, если мы хотим создать очередь из отдельных задач.
Если вдруг ваше приложение системное, либо же у вас есть несколько приложений с одним sharedUserId, то нужно учитывать дополнительное условие: id не должен пересекаться среди всех приложений с одним uid. Таким образом, если приложение использует android.uid.system, то нужно учитывать, что некоторые системные задачи также используют JobScheduler, и уникальность id нужно поддерживать самостоятельно.
Кстати, при использовании таких методов у JobScheduler как removeAll() мы можем удалить и чужие задачи с тем же uid.
Статья на английском о том, как можно контролировать подобную ситуацию.
В рассматриваемом примере не нужно забоится об UID и в качестве идентификатора используется инкрементируемое значение sJobId.
sJobId определен следующим образом:
С ComponentName все гораздо проще, это объект в конструктор которого передается ExerciseJobService.class.
Инициализация параметров с помощью JobInfo.Builder
Ниже рассмотрим основной набор методов JobInfo.Builder.
минимальное время, которое пройдет прежде чем задача будет выполнена, другими словами время отложенного старта.
максимальное время, в течение которого задача может находиться в очереди / запланированном состоянии. Если по истечению 5 секунд (в нашем случае) благоприятные условия так и не наступили, задача начнет выполняться ни смотря ни на что (если это не противоречит другим политикам JobScheduler). Если не использовать, тогда задача будет выполнена только при наступлении необходимых условий.
задается тип подключения, например, нам нужен интернет, но чтобы это был свободный WIFi (не hotspot) или Ethernet, тогда мы выбираем NETWORK_TYPE_UNMETERED .
Определяет состояние, когда пользователь не взаимодействует с устройством, в нашем случае это не важно.
В нашем примере предположим, что нам без разницы, заряжается устройство или нет.
Можно установить для задачи критерий повтора (подробнее об этом чуть ниже):
Кроме этого есть возможность сделать задачу периодической:
Периодические задачи
Когда мы устанавливаем задаче периодичность, мы сталкиваемся с логичными ограничениями:
- setMinimumLatency() и setOverrideDeadline() использовать нельзя, так как не имеет смысла — задача так или иначе должна выполниться один раз в течение заданного интервала, и никакие дополнительные ограничения сверху или снизу недопустимы. С другой стороны иногда нам нужно чего-то подождать, а потом начинать периодическую задачу — здесь добавить такое условие нельзя, если нужно ждать, значит ждать нужно до того, как добавлять задачу на выполнение.
- в JobService в onStopJob() нам можно не возвращать true — прерванная периодическая задача не будет удалена из очереди, в следующий раз она выполнится по расписанию.
- никто не гарантирует, что задача будет выполнена ровно через заданный интревал, она просто будет выполнена не более чем 1 раз за этот интервал.
Это основные отличия периодической задачи от обычной. В текущем примере мы не будем делать задачу периодической.
Критерий повтора выполнения задачи
setBackoffCriteria() позволяет задать правило, по которому будет произведена повторная попытка выполнения задачи в случае необходимости (например в onStopJob() мы вернули true).
JobScheduler предлагает нам две политики: линейная и экспоненциальная.
Формула линейной политики следующая:
т.е. от текущего момента времени следующая попытка будет предпринята через заданное количество времени умноженное на количество неудач.
Формула экспоненциальной политики:
Здесь же время следующей попытки растет гораздо большими шагами.
Все достаточно просто и прозрачно, но что будет, если наша задача не может выполниться успешно множество раз, 10, 20. При заданном начальном времени повтора в 1 минуту к 10 попытке пройдет практически час. Отлавливать такие ситуации достаточно не просто, потому что мы не можем предсказать что будет через час. JobScheduler ограничивает такие повтороения пятью часами.
Таким образом с параметром setBackoffCriteria() нужно обращаться очень осторожно, тщательно продумывать начальное время и тип политики в соотвествии с поставленными задачами. Возможно также придется осуществлять дополнительную обработку, например, количества повторов и удалять задачу из JobScheduler.
Отправка задачи на выполнение
Таким образом у нас готов JobBuilder со всеми необходимыми нам параметрами. Для добавления задачи в очередь выполнения необходимо получить у системы инстанс JobScheduler:
И вызвать метод для добавления JobInfo из билдера:
Для надежности можно проверить возвращаемое значение последнего метода, который нам скажет об успешном или не успешном добавлении задачи в очередь.
Далее когда JobScheduler находит, что условия для выполнения задачи оптимальные, вызывается метод onStartJob() в ExerciseJobService, который уже разобран выше.
Проверка и отладка
Если подытожить, то в результате у нас получилось тестовое приложение, которое позволяет планировать одноразовые задачи, которые выполняют условно-тяжелую операцию в IntentService.
Для проверки работоспособности предлагаю добавить небольшой инструментальный тест, который выглядит примерно так:
Также, для проверки работы примера в исходный код были добавлены некоторые логи, которые не указаны выше в выдержках.
Если мы запустим тест, то мы увидим, что наша задача с "id: 1" стартует и завершается, стартует и завершается… Точнее её принудительно завершает JobScheduler.
Выполнение задачи в отдельных потоках и оповещение сервиса о завершении
В данном примере из метода onStartJob() мы вернули true, а это значит, что мы сообщили JobScheduler'у что выполнение задачи продолжается где-то в побочном потоке. Так как мы не уведомляем о завершении задачи, JobScheduler завершает её принудительно, а так как из onStopJob() мы тоже возвращаем true срабатывает политика повтора, и задача перепланируется и запускается заново.
Чтобы такого не происходило, нужно вызывать метод jobFinished() в классе сервиса ExerciseJobService, о его использовании и различных вариантах передачи информации о завершении задачи из IntentService я постараюсь рассказать в следующих статьях.
На этом создание тестового примера завершается, он готов к использованию и применению в рабочих проектах для планирования задач. Для выполнения задач в фоне здесь был использован IntentService, но допустимы и другие способы, например, использование ThreadPoolExecutor или HandlerThread. А в случае разработки исключительно под Android O и выше, рекомендую также обратить внимание на JobIntentService.
Полный код рассматриваемого примера приведен на GitHub.
Иллюстрация: Anni ART (копирование и воспроизведение только с согласия автора).
Привет Хабр! Предлагаю вашему вниманию свободный перевод статьи «Schedule tasks and jobs intelligently in Android» от Ankit Sinhal.
В современной разработке приложений очень часто выполняются задачи асинхронно, и их объем выходит за пределы жизненного цикла приложения. В некоторых ситуациях мы также должны выполнять некоторые работы, но это не обязательно делать прямо сейчас. Чтобы запланировать фоновые работы, Android представила несколько API, которые мы можем грамотно использовать в наших приложениях.
Выбор подходящего планировщика может улучшить производительность приложений и время автономной работы устройства.
Для планирования задач на Android доступно несколько API:
- Alarm Manager
- Job Scheduler
- GCM Network Manager
- Firebase Job Dispatcher
- Sync Adapter
Проблемы с сервисами
Сервисы позволяют выполнять длительные операции в фоновом режиме. Запуск сервисов в фоновом режиме очень негативно влияет на заряд батареии.
Сервисы особенно вредны, когда они постоянно использует ресурсы устройства, даже если не выполняет полезные задачи.
Запланированный задачи во время жизненного цикла приложения
Когда приложение запущено, и мы хотим запланировать или запустить задачу в определенное время, рекомендуется использовать класс Handler вместе с Timer и Thread.
Запланированные задачи при выключенном приложении
Alarm Manager
AlarmManager обеспечивает доступ к службам уведомлений. Это дает возможность выполнять любые операции за пределами жизненного цикла вашего приложения. Таким образом, вы можете инициировать события или действия, даже если ваше приложение не запущено. AlarmManager может запустить сервис в будущем.
Мы должны использовать API AlarmManager только для задач, которые должны выполняться в определенное время
Пример использования: предположим, что мы хотим выполнить задачу через 1 час или каждый час. В этом случае AlarmManager нам поможет.
Job Scheduler
Это главный из всех упомянутых вариантов планирования и очень эффективный с фоновыми работами. JobScheduler API, который был представлен в Android 5.0 (API уровня 21).
Этот API позволяет выполнять задания, когда у устройства больше доступных ресурсов или при соблюдении правильных условий. Все условия могут быть определены при создании задания. Когда объявленные критерии будут выполнены, система выполнит это задание в JobService вашего приложения. JobScheduler также отменяет выполнение, если необходимо, чтобы соблюдать ограничения режима Doze и App Standby.
GCM Network Manager
GCM (Google Cloud Messaging) Network Manager имеет все функции расписания из JobScheduler. GCM Network Manager также предназначен для выполнения многократной или одноразовой, неминуемой работы при сохранении времени автономной работы.
Он используется для поддержки обратной совместимости и может также использоваться под Android 5.0 (API уровня 21). Начиная с уровня API 23 или выше, GCM Network Manager использует JobScheduler для платформы. GCM Network Manager использует механизм планирования в службах Google Play, поэтому этот класс будет работать только в том случае, если на устройстве установлены сервисы Google Play.
Google настоятельно рекомендовал пользователям GCM перейти на FCM и вместо этого использовать диспетчер заданий Firebase для планирования любых задач.
Firebase Job Dispatcher
Firebase JobDispatcher также является библиотекой для планирования фоновых заданий. Он также используется для поддержки обратной совместимости (ниже API 21) и работает во всех последних версиях Android (API 9+).
Эта библиотека также будет работать, если на устройстве нет установленных сервисов Google Play. В этом состоянии эта библиотека внутренне использует AlarmManager. Если на устройстве доступно приложение Google Play, он использует механизм планирования в службах Google Play.
Sync Adapter
Sync adapters разработаны специально для синхронизации данных между устройством и облаком. Он должен использоваться только для этого типа задач. Синхронизация может быть вызвана изменениями данных в облаке или на устройстве или по истекшему времени.
Система будет пытаться синхронизировать только тогда, когда устройство подключено к сети.
Упражнение
Мы обсудили достаточно теории, поэтому теперь посмотрим, как использовать планировщик заданий Android.
Создание Job Service
Создайте JobSchedulerService extends JobService, который требует, чтобы были созданы два метода onStartJob (параметры JobParameters) и onStopJob (параметры JobParameters).
Метод onStartJob вызывается, когда JobScheduler решает запустить вашу работу. JobService работает в основном потоке, поэтому любая логика должна выполняться в отдельном потоке. Метод onStopJob вызывается, если система решила, что вы должны прекратить выполнение своей работы. Метод вызывается до jobFinished (JobParameters, boolean).
Вам также необходимо зарегистрировать свою службу в AndroidManifest.
Создать объект JobInfo
Чтобы построить объект JobInfo, передайте JobService в JobInfo.Builder (), как показано ниже. Этот конструктор заданий позволяет установить множество различных параметров управления при выполнении задания.
Запланированная задача
Теперь у нас есть JobInfo и JobService, поэтому пришло время планировать нашу работу. Все, что нам нужно сделать, это запланировать работу с требуемой JobInfo, как показано ниже:
Заключение
При планировании задания вам нужно тщательно подумать о том, когда и что должно вызвать вашу задачу, и что должно произойти, если она по какой-то причине не сработает. Вы должны быть очень осторожны с производительностью вашего приложения, а также с другими аспектами, такими как заряд батареи.
JobScheduler легко реализуется и обрабатывает большую часть за вас. При использовании JobScheduler наши запланированные задания сохраняются, даже если система перезагружается. В настоящий момент единственным недостатком JobScheduler является то, что он доступен только для 21 уровня api (Android 5.0).
Читайте также: