How to work android mobile

Урок 29. WorkManager. Введение

В этом уроке знакомимся с WorkManager.

Полный список уроков курса:

Немаловажная часть работы приложения — это фоновая работа. Это может быть загрузка или аплоад, сжатие или распаковка, синхронизация и т.п. Когда-то давно для фоновой работы были предназначены сервисы. Но в Android 8 их очень сильно ограничили: если приложение не активно, то и сервис будет остановлен через какое-то время. Да и еще задолго до Android 8 разработчики начали использовать такие инструменты как JobScheduler или Firebase JobDispatcher для запуска фоновых задач.

WorkManager — новый инструмент. Он позволяет запускать фоновые задачи последовательно или параллельно, передавать в них данные, получать из них результат, отслеживать статус выполнения и запускать только при соблюдении заданных условий.

При этом он очень простой в использовании. Я рассчитываю, что мне хватит 4 небольших урока, чтобы рассмотреть все его возможности.

Задача

Давайте создадим и запустим фоновую задачу.

Добавьте в dependencies

Создаем класс, наследующий класс Worker:

В метод doWork нам предлагается поместить код, который будет выполнен. Я здесь просто ставлю паузу в 10 секунд и возвращаю результат SUCCESS, означающий, что все прошло успешно. Нам не надо заморачиваться с потоками, т.к. код будет выполнен не в UI потоке.

Задача готова. Теперь нам нужно MyWorker обернуть в WorkRequest:

WorkRequest позволяет нам задать условия запуска и входные параметры к задаче. Пока что мы ничего не задаем, а просто создаем OneTimeWorkRequest, которому говорим, что запускать надо будет задачу MyWorker.

OneTimeWorkRequest не зря имеет такое название. Эта задача будет выполнена один раз. Есть еще PeriodicWorkRequest, но о нем чуть позже.

Теперь можно запускать задачу:

Берем WorkManager и в его метод enqueue передаем WorkRequest. После этого задача будет запущена.

20:37:36.567 5369-5444 doWork: start
20:37:46.568 5369-5444 doWork: end

Видно, что задача выполнялась 10 секунд, и код выполнялся не в UI потоке.

Статус задачи

WorkManager предоставляет возможность отслеживать статус выполнения задачи. Например в Activity пишем:

В метод getStatusById необходимо передать ID задачи, который может быть получен методом WorkRequest.getId. В результате мы получаем LiveData, подписываемся на него и в метод onChanged нам будут приходить все изменения статуса нашей задачи. Методом WorkStatus.getState будем получать текущее состояние.

20:52:54.189 6060-6060 onChanged: ENQUEUED
20:52:54.199 6060-6087 doWork: start
20:52:54.203 6060-6060 onChanged: RUNNING
20:53:04.200 6060-6087 doWork: end
20:53:04.211 6060-6060 onChanged: SUCCEEDED

Сразу после вызова метода enqueue задача находится в статусе ENQUEUED. Затем WorkManager определяет, что задачу можно запускать и выполняет наш код. В этот момент статус меняется на RUNNING. После выполнения статус будет SUCCEEDED, т.к. мы вернули такой статус в методе doWork.

Статус нам приходит в UI потоке.

Теперь еще раз запустим задачу и закроем приложение:

20:58:19.402 doWork: start
20:58:19.424 onChanged: ENQUEUED
20:58:19.462 onChanged: RUNNING
20:58:29.403 doWork: end

Обратите внимание, задача завершилась, а статус SUCCEEDED не пришел. Почему? Потому что, закрыв Activity мы всего лишь отписались от LiveData, который передавал нам статусы задачи. Но сама задача никуда не делась. Она никак не зависит от приложения и будет выполняться, даже если приложение закрыто.

Результат

Мы в нашей задаче возвращали статус WorkerResult.SUCCESS, тем самым сообщая, что все ок. Есть еще два варианта:

FAILURE — в этом случае после завершения задачи workStatus.getState вернет FAILED. Для нас это сигнал, что задача не была выполнена.

RETRY — а этот результат является сигналом для WorkManager, что задачу надо повторить. В этом случае workStatus.getState вернет нам статус ENQUEUED — т.е. задача снова запланирована.

Я протестировал на эмуляторе поведение при RETRY: первый раз задача была перезапущена примерно через одну минуту после предыдущего завершения. С каждым последующим перезапуском интервал увеличивался:

21:10:22.637 doWork: start
21:10:32.638 doWork: end
21:11:32.655 doWork: start
21:11:42.657 doWork: end
21:14:07.538 doWork: start
21:14:17.543 doWork: end
21:18:17.561 doWork: start
21:18:27.602 doWork: end
21:26:27.618 doWork: start
21:26:37.653 doWork: end

Отмена задачи

Мы можем отменить задачу методом cancelWorkById, передав ID задачи

При этом в классе MyWorker будет вызван метод onStopped (если вы его реализовали). Также в классе MyWorker мы всегда можем использовать boolean метод isStopped для проверки того, что задача была отменена.

Если отслеживаем статус задачи, то WorkStatus.getState вернет Cancelled.

Также есть метод cancelAllWork, который отменит все ваши задачи. Но хелп предупреждает, что он крайне нежелателен к использованию, т.к. может зацепить работу библиотек, которые вы используете.

Читайте также:  Onenote для андроид как пользоваться

Задаче можно присвоить тег методом addTag:

Одной задаче можно добавлять несколько тегов.

У WorkStatus есть метод getTags, который вернет все теги, которые присвоены этой задаче.

Присвоив один тег нескольким задачам, мы можем всех их отменить методом cancelAllWorkByTag:

setInitialDelay

Выполнение задачи можно отложить на указанное время

В методе setInitialDelay мы указали, что задачу следует запустить через 10 секунд после передачи ее в WorkManager.enqueue

Периодическая задача

Рассмотренный нами OneTimeWorkRequest — это разовая задача. А если нужно многократное выполнение через определенный период времени, то можно использовать PeriodicWorkRequest:

В билдере задаем интервал в 30 минут. Теперь задача будет выполняться с этим интервалом.

Минимально доступный интервал — 15 минут. Если поставите меньше, WorkManager сам повысит до 15 минут.

WorkManager гарантирует, что задача будет запущена один раз в течение указанного интервала. И это может случиться в любой момент интервала — через 1 минуту, через 10 или через 29.

С помощью параметра flex можно ограничить разрешенный диапазон времени запуска.

Кроме интервала в 30 минут дополнительно передаем в билдер flex параметр 25 минут. Теперь задача будет запущена не в любой момент 30-минутного интервала, а только после 25-й минуты. Т.е. между 25 и 30 минутами.

Context

Чтобы получить Context в Worker классе, используйте метод getApplicationContext.

Перезагрузка

Что происходит с запланированными задачами при перезагрузке устройства? Я протестил этот кейс на эмуляторе и выяснил, что все задачи сохраняются. Т.е. OneTimeWorkRequest c отложенным запуском, OneTimeWorkRequest с результатом RETRY, PeriodicWorkRequest — все эти задачи будут снова запущены после перезагрузки устройства.

Поэтому действуйте обдуманно и храните где-то у себя ID или тэг задачи, чтобы вы могли ее отменить, если она вам больше не нужна.

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Android for Work: Android OS для деловых людей

По данным компании Google, сейчас около миллиарда человек пользуется смартфонами с Android OS. При этом смартфоны стали действительно универсальным инструментом, позволяющим и работать, и развлекаться, и общаться с близкими, друзьями. коллегами. Для многих людей мобильные устройства с Android стали надежным инструментом для работы, при помощи смартфонов сейчас можно проверять почту, редактировать документы, проверять статистику продаж и заключать сделки.

Тем не менее, многие деловые люди недооценивают возможности смартфонов и планшетов для работы, несмотря на то, что возможности Android достаточно обширны в этом плане. Понимая проблему, разработчики создали специальный пакет Android for Work, созданный при участии большого количества партнеров. По замыслу авторов проекта, Android for Work поможет представителям бизнеса работать более эффективно с мобильными устройствами, используя этот пакет.

Возможности Android for Work:

Рабочие профили. Android for Work есть шифрование по умолчанию, продвинутые инструменты безопасности из SELinux, с нативной поддержкой нескольких профилей в Android 5.0 (Lollipop является основой пакета). Теперь можно работать с различными профилями, изолированными друг от друха. Представители IT-сектора могут разворачивать приложения для работы, оставляя свои личные данные в безопасности. Пользователи теперь могут использовать личные приложения, зная, что начальство может работать только с корпоративными приложениями, не затрагивая личные данные пользователей.

Приложение Android for Work для ОС Android 4.0 Ice Cream Sandwich и новее. Для более старых версий Android, Ice Cream Sandwich или Kitkat, где нет нативной работы с профилями, будет создано приложение Android for Work. Это приложение позволит осуществлять безопасную работу с почтой, календареи, контактами, документами, разделяя рабочую информацию и личные данные.

Google Play for Work. Этот пакет позволяет бизнесу безопасно разворачивать и управлять приложениями в пакетах Android for Work, установленных на смартфонах и планшетах сотрудников. При этом процесс установки приложений для сотрудников значительно упрощен, а личные данные, как и указывалось выше, не затрагиваются.

Встроенные инструменты повышения производительности. Для эффективного выполнения ежедневных задач разработчики предусмотрели ряд бизнес-приложений для почты, контактов и календаря, совместымых с Exchange и Notes. Также инструменты позволяют эффективно работать с текстовыми документами, таблицами и презентациями.

При работе над Android for Work корпорация Google привлекла к сотрудничеству большое количество партнеров:

Платформа Android for Work уже доступна, и корпорация Google планирует совершенствовать этот пакет, делая ее более универсальным и эффективным инструментом для бизнеса.

Читайте также:  Геймпад для андроид топ 2021

Источник

Фоновая работа в Android: обзор возможностей WorkManager

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

Например, в ритейле мерчендайзерам бывает необходимо в конце каждого рабочего дня отправлять фотоотчеты на сервер и удалять их из памяти телефона, чтобы не занимать место. А для работы онлайн-кассы требуется в фоновом режиме загружать актуальный справочник товаров. В этой статье мы рассмотрим один из самых популярных инструментов для реализации фоновой работы – WorkManager из Android Jetpack.

Для фоновой работы в Android существует множество изначально реализованных нативных решений, таких как AlarmManager, Handler, IntentService, SyncAdapter, Loader. Однако, их судьба складывается по-разному:

Handler до сих пор повсеместно используется, но, в основном, для посылки эвентов в очередь событий главного потока.

На действия AlarmManager система Android накладывает все больше ограничений, также он имеет довольно раздутое API для работы.

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

Loader имеет привязку к жизненному циклу Activity/Fragment и, с появлением более новых, удобных инструментов, позволяющих решать схожие задачи, морально устарел.

SyncAdapter также морально устарел, не имеет возможности задавать условия запуска задач, создавать цепочки задач.

Начиная с Android 5.0 появился JobScheduler, позволяющий задавать условия запуска задач (устройство на зарядке, подключено к wi-fi и т.д.). Его работа основана на Service, и, чтобы обработка прошла асинхронно, необходимо самостоятельно запустить рабочий поток, а также вызвать необходимые методы JobService для избежания утечек. Все описанное повышает вероятность ошибок и доступно только с api 21.

Учитывая перечисленные ограничения, разработчики столкнулись с потребностью в таком инструменте, который может инкапсулировать работу по избежанию утечек и обращению с потоками, а также предоставить удобное API для запуска асинхронных, повторяющихся, откладываемых задач. В результате в 2018 году был выпущен Android Jetpack, частью которого стал WorkManager (познакомиться с ним подробнее можно, в частности, здесь).

Далее рассмотрим подробнее особенности работы.

WorkManager предоставляет удобные инструменты для описанных выше задач, совместим с корутинами, RxJava2, другими Jetpack библиотеками, может работать в мультипроцессном режиме. Доступен он начиная с API 14 за счет использования под капотом уже знакомых инструментов.

1) Описание и добавление задачи

Для описания задачи необходимо унаследоваться от класса Worker и определить метод doWork():

Код внутри метода doWork() будет выполнен в рабочем потоке WorkManager’a.

Далее задачу можно сделать разовой с помощью OneTimeWorkRequestBuilder.

Либо ее можно сделать периодической с помощью PeriodicWorkRequestBuilder.

В обоих случаях мы передали в качестве generic-параметра класс Worker’a, определенный нами.

В случае периодической задачи мы дополнительно определили интервал ее выполнения — 30 минут (минимально доступный интервал составляет 15 минут; если мы поставим интервал меньше 15 минут, то WorkManager повысит его до 15). А также параметр flex — 25 минут. Этот параметр ограничивает окно запуска задачи: она будет запущена не в любой момент интервала, а между 25 и 30 минутами.

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

После создания задачи мы добавляем ее в очередь WorkManager’a.

2) Критерии запуска задачи

Мы можем задать необходимые условия для запуска задачи:

После этого констрейнты добавляются в билдере work request’a.

Рассмотрим перечисленные условия запуска:

setRequiresCharging (boolean requiresCharging) — критерий: зарядное устройство должно быть подключено.

setRequiresBatteryNotLow (boolean requiresBatteryNotLow) — критерий: уровень батареи не ниже критического (задача начинает выполняться при уровне заряда больше 20, а останавливается при значении меньше 16).

setRequiredNetworkType (NetworkType networkType) — критерий: наличие интернета. Мы можем указать, какой именно тип сети интернет (NetworkType) должен быть при запуске задачи. Тип соединения с сетью может быть:

CONNECTED — WiFi или Mobile Data

UNMETERD — только WiFi

METERED — только Mobile Data

NOT_ROAMING — интернет не должен быть роуминговым;

NOT_REQUIRED — интернет не нужен.

setRequiresDeviceIdle (boolean requiresDeviceIdle) — критерий: девайс не используется какое-то время и ушел “в спячку”. Работает на API 23 и выше.

setRequiresStorageNotLow (boolean requiresStorageNotLow) — критерий: на девайсе должно быть свободное место, не меньше критического порога.

3) Цепочки задач

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

Периодические задачи ставить в цепочку нельзя.

В данном примере мы параллельно запускаем задачи myWorkRequest1, myWorkRequest2. После их выполнения будут параллельно выполняться задачи myWorkRequest3, myWorkRequest4. Затем — задача myWorkRequest5. Данный пример можно переписать, выделив параллельные запросы в цепочки. После чего две получившиеся цепочки можно передать в метод combine() класса WorkContinuation для параллельного исполнения:

Читайте также:  Смс андроид команды нет

4) Уникальная цепочка задач

Мы можем сделать последовательность задач уникальной. Для этого нужно начать последовательность методом beginUniqueWork():

В этот метод мы передали название уникальной цепочки, стратегию действий при коллизии цепочек с одинаковым именем и саму задачу (можно передать список задач).

Стратегий может быть несколько:

REPLACE – остановка последовательности с таким же именем, и запуск новой;

KEEP – оставит в работе текущую выполняемую последовательность, а новая будет проигнорирована;

APPEND – запустит новую последовательность после выполнения текущей.

5) Отмена задачи

Для отмены задачи у класса WorkManager есть следующие методы:

cancelAllWork() — отменяет все запланированные задачи (и не только вашим приложением);

cancelAllWorkByTag(String tag) — отменяет все задачи с указанным тегом;

cancelUniqueWork(String uniqueWorkName) — отменяет уникальную цепочку задач с указанным именем;

cancelWorkById(UUID id) — отменяет задачу по указанному id.

6) Статусы задач

Статусы и жизненный цикл задачи может быть различным, в зависимости от того, разовая она или нет. Возможны следующие статусы задач:

ENQUEUED – задача запланирована;

RUNNING – задача выполняется;

SUCCEEDED (SUCCESS) – задача выполнена, терминальное состояние;

FAILED (FAILURE) – задача не была выполнена, не повторять, терминальное состояние;

RETRY – задача не была выполнена, повторить через некоторое время;

BLOCKED – задача включена в цепочку, и ее очередь выполнения еще не наступила;

CANCELLED – задача отменена, терминальное состояние.

Для разовой задачи возможен следующий флоу:

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

Для периодической задачи существует другой флоу:

Как мы видим, для периодической задачи существует одно терминальное состояние: CANCELLED.

Так как WorkManager является частью Jetpack, получить информацию о задаче можно в виде LiveData:

7) Входные и выходные данные задачи

Мы можем задать входные данные, необходимые для ее работы.

Когда задача будет запущена, мы сможем получить эти данные внутри нее с помощью:

После выполнения мы можем в Result.success() или Result.failure() передать выходные данные задачи.

8) Передача данных между задачами

При создании цепочки задач выходные данные одной задачи будут передаваться во входные данные другой. Рассмотрим такой пример. Пусть задачи myWorkRequest1 и myWorkRequest2 выполняются параллельно, затем выполняется myWorkRequest3. В результате выходные данные из первой и второй задач попадут в третью.

Так как мы задали одинаковые ключи, невозможно предположить, какое именно значение попадет в третью задачу, ведь первая и вторая задача выполняются параллельно. Важно об этом помнить.

9) InputMerger

Для преобразования нескольких выходных результатов в один входной используются реализации класса InputMerger. По умолчанию используется OverwritingInputMerger, перезаписывающий значение по уже существующему ключу. Это было видно на предыдущем примере с двумя параллельными задачами. Если же нам нужно при совпадении ключа записать все пришедшие значения, следует использовать ArrayCreatingInputMerger.

InputMerger можно задать при создании задачи. Добавим ArrayCreatingInputMerger для myWorkRequest3 из предыдущего примера.

Теперь по ключу keyA мы получим не последнее записанное значение, а массив [«value1», «value2»]. Также и для ключа keyB — [1, 2].

10) Кастомная конфигурация WorkManager

WorkManager имеет собственный провайдер, WorkManagerInitializer, который мержится в манифест приложения. Он создает пул потоков, необходимый для работы, фабрики для создания InputMerger’ов и WorkerFactory (создает объекты Worker’ов, полезна в случаях, когда класс Worker’a получил новое имя, и WorkManager должен соотнести действия, запланированные на старое имя, с новым). При необходимости эти параметры можно изменить.

Для начала нужно отключить стандартный провайдер WorkManager’a. Это делается в манифесте приложения путем объявления.

После этого нужно сделать класс нашего приложения реализацией интерфейса Configuration.Provider. И в переопределенном методе изменить нужные нам параметры. Например, заменим стандартный Executor, в потоках которых выполняется код Worker’ов, и изменим минимальный уровень логирования:

11) Тестирование

Для тестирования Worker’ов нужно подключить в проект зависимость

В этом пакете есть классы, которые помогают в тестовой среде.

Пусть у нас есть Worker, который складывает 2 числа и выдает результат в качестве выходных данных. Протестируем его:

Дополнительно можно проверить, что код Worker’a выполняется только тогда, когда выполнены все условия его запуска. А также проверить статус работы.

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

Заключение

WorkManager предоставляет широкие возможности для асинхронной работы, которая должна выполняться в определенном состоянии устройства, откладывать ее, планировать, выполнять параллельно, перезапускать, запускать периодически, работать в многопроцессном режиме. Также этот инструмент гарантирует выполнение задачи даже после закрытия приложения и перезагрузки устройства. А его доступность, начиная с API 14, делает его must-have инструментом для подобного рода задач.

Спасибо за внимание! Надеемся, что этот материал был полезен для вас.

Источник

Оцените статью