Work manager or service android

When to use JobIntentService vs WorkManager?

The docs for IntentService now say:

So what are the differences between JobIntentService and WorkManager and which one is recommended under which circumstances?

Google doesn’t even mention JobIntentService on this page, they only mention WorkManager: https://developer.android.com/guide/background

1 Answer 1

Since Android Oreo we cannot keep normal Services running on the background anymore, because the system will:

1-kill the service after around one minute if the app itself goes to the background after launching the service

2-throw an exception if the service was launched when the app itself is in the background

IntentService is just a subclass of the normal service, which executes all its work sequentially on a background thread and stops itself when it finishes executing all its work. But as a service, it is, as well, affected by the limitations mentioned above.

Now for the JobIntentService:

Will act as a normal IntentService on pre-Oreo Devices (because we don’t have any limitations) and on Oreo+ will use jobScheduler instead to achieve similar behavior as IntentService. It just starts the work as soon as possible, schedules its work via JobScheduler, and JobScheduler may elect to postpone that work for a bit, but its job are more likely to be differed or interrupted in low-memory situtations ,in doze mode or when they reach a time limit(

With JobIntentService, doing some configurations is impossible, like defining specifically under which circumstances we want our jobs to start (such as when the device is currently Charging or if we have WIFI connection), however with workmanager we can set these constraints.

Use WorkManager for jobs that have some Constraints,or for jobs/work that are transactional not ongoing, or for jobs that can happen sometime in the future, and use JobIntentService when you want to copy the behavior of the normal IntentService on Android Oreo+ and for jobs that can be slightly delayed and might take more than 1 minute but less than 10 minutes approx.

Источник

Foreground service vs WorkManager for location tracking

Let’s say I want to build an app which requests current location periodically (e.g., every 10 minutes, this number should be configurable) and submits to a server.

I’m aware that Foreground Service and WorkManager are normally suggested for this kind of scenario. However which is would suit more? Below are my thoughts and doubts.

WorkManager — is mainly for deferrable background work whose execution is guaranteed. However I know that from Android 8 (API 26) background location was introduced and that restrict location to be updated only a few times every hour https://developer.android.com/about/versions/oreo/background-location-limits. Thus this perhaps doesn’t meet the periodical updates as per the requirement.

ForegroundService — is perfect for something that runs and needs to make users aware of. It’s recommended for this kinda scenario (location tracking) for privacy purpose. Google also creates a sample app to promote this practice https://github.com/android/location-samples/tree/master/LocationUpdatesForegroundService.

From the above analysis, it seems ForegroundService is the one. However I also found that WorkManager has a built-in support to use Worker in conjunction with ForegroundService via androidx.work.impl.foreground.SystemForegroundService https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running#long-running-kotlin

That makes me confused as to what should I use and what Google really recommend for this specific scenario.

Источник

Эволюция планировщиков задач

Приложение iFunny, над которым мы работаем, доступно в сторах уже более пяти лет. За это время мобильной команде пришлось пережить множество разных подходов и миграций между инструментами, а год назад появилось время перейти с самописного решения и посмотреть в сторону чего-то более «модного» и распространённого. Эта статья — небольшая выжимка о том, что было изучено, на какие решения смотрели и к чему в итоге пришли.

Зачем нам это всё?

Давайте сразу определимся, в честь чего эта статья и почему эта тема оказалась важной для команды Android-разработки:

  1. есть множество сценариев, когда необходимо запускать задачи вне рамок активного пользовательского интерфейса;
  2. система накладывает большое количество ограничений на запуск подобных задач;
  3. выбрать между существующими решениями оказалось довольно сложно, так как каждый инструмент имеет свои плюсы и минусы.
Читайте также:  Как удалить премиум с гет контакта андроид

Хронология развития событий

AlarmManager, Handler, Service


Изначально были реализованы свои решения для запуска бэкграунд-задач на основе сервисов. Также был механизм, который привязывал задачи к жизненному циклу и умел отменять и восстанавливать их. Команду это долгое время устраивало, так как никаких ограничений платформа к таким задачам не предъявляла.
В Google же советовали это делать, опираясь на следующую диаграмму:

В конце 2018 года разбираться в этом уже нет смысла, достаточно оценить масштабы бедствия.
Фактически никого не заботило, как много работы происходит в фоне. Приложения делали что хотели и когда хотели.

Плюсы:
доступно везде;
доступно для всех.

Минусы:
система всячески ограничивает работу;
нет запусков по условию;
API минимальное и нужно писать много кода.

Android 5. Lollipop

JobScheduler


Спустя 5(!) лет, ближе к 2015 году в Google заметили, что задачи запускаются неэффективно. Пользователи стали регулярно жаловаться, что их телефоны разряжаются, просто лёжа на столе или в кармане.

С выходом Android 5 появился такой инструмент, как JobScheduler. Это механизм, с чьей помощью можно в фоне выполнять различную работу, начало выполнения которой оптимизировалось и упрощалось за счёт централизованной системы запуска этих задач и возможности задавать условия для этого самого запуска.

В коде всё это выглядит достаточно просто: объявляется сервис, в который приходят события старта и конца работы.
Из нюансов: если вы хотите выполнить работу асинхронно, то из onStartJob нужно запустить поток; главное не забыть вызвать метод jobFinished по окончанию работы, иначе система не отпустит WakeLock, ваша задача не будет считаться выполненной и утечёт.

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

В общем, по сравнению с ничем это было уже кое-что. Но этот механизм доступен только с API 21, и на момент выхода Android 5.0 было бы странно перестать поддерживать все старые девайсы (прошло 3 года, а мы до сих пор поддерживаем четвёрки).

Плюсы:
API простое;
условия для запуска.

Минусы:
доступно начиная с API 21;
фактически только с API 23;
легко ошибиться.

Android 5. Lollipop

GCM Network Manager


Также был представлен аналог JobScheduler — GCM Network Manager. Это библиотека, которая предоставляла схожий функционал, но работала уже с API 9. Правда, взамен требовала наличие Google Play Services. Видимо, функционал, необходимый для работы JobScheduler, стали поставлять не только через версию Android, но и на уровне GPS. Надо отметить, что разработчики фреймворка очень быстро одумались и решили не связывать своё будущее с GPS. Спасибо им за это.

Выглядит всё абсолютно идентично. Такой же сервис:

Такой же запуск задач:

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

Плюсы:
API, аналогичное JobScheduler;
доступно начиная с API 9.

Минусы:
необходимо иметь Google Play Services;
легко ошибиться.

Android 5. Lollipop

WakefulBroadcastReceiver


Далее напишу пару слов об одном из базовых механизмов, который используется в JobScheduler и доступен разработчикам напрямую. Это WakeLock и основанный на нём WakefulBroadcastReceiver.

С помощью WakeLock можно запретить системе уходить в suspend, то есть держать девайс в активном состоянии. Это необходимо, если мы хотим выполнить какую-то важную работу.
При создании WakeLock можно указать его настройки: держать CPU, экран или клавиатуру.

На основе этого механизма работает WakefulBroadcastReceiver. Мы запускаем сервис и удерживаем WakeLock.

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

Через 4 версии этот BroadcastReceiver станет deprecated, и на developer.android.com будут описаны следующие альтернативы:

  • JobScheduler;
  • SyncAdapter;
  • DownloadManager;
  • FLAG_KEEP_SCREEN_ON для Window.

Android 6. Marshmallow

DozeMode: сон на ходу


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

Первым делом появился DozeMode, который переводит устройство в спящий режим, если оно лежало без действий определённое время. В первых версиях это длилось час, в последующих длительность сна уменьшили до 30 минут. Периодически телефон просыпается, выполняет все отложенные задачи и снова засыпает. Окно DozeMode увеличивается экспоненциально. Все переходы между режимами можно отследить через adb.

Читайте также:  Lego marvel super heroes android mod

При наступлении DozeMode на приложение накладываются следующие ограничения:

  • система игнорирует все WakeLock;
  • откладывается AlarmManager;
  • JobScheduler не работает;
  • SyncAdapter не работает;
  • доступ в сеть ограничен.

Также вы можете добавить ваше приложение в whitelist, чтобы оно не попадало под ограничения DozeMode, но как минимум Samsung полностью игнорировал этот список.

Android 6. Marshmallow

AppStandby: неактивные приложения


Система определяет приложения, которые являются неактивными, и накладывает на них все те же ограничения, что и в рамках DozeMode.
Приложение отправляется в изоляцию, если:

  • не имеет процесса на переднем плане;
  • не имеет активной нотификации;
  • не добавлено в список исключений.

Android 7. Nougat

Background Optimizations. Svelte


Svelte — это проект, в рамках которого Google пытается оптимизировать потребление оперативной памяти приложениями и самой системой.
В Android 7 в рамках этого проекта было решено, что неявные бродкасты не очень эффективны, так как их слушает огромное количество приложений и система тратит большое количество ресурсов при наступлении этих событий. Поэтому следующие типы событий были запрещены для объявления в манифесте:

  • CONNECTIVITY_ACTION;
  • ACTION_NEW_PICTURE;
  • ACTION_NEW_VIDEO.

Android 7. Nougat

FirebaseJobDispatcher


В это же время была опубликована новая версия фреймворка для запуска задач — FirebaseJobDispatcher. На самом деле это был дописанный GCM NetworkManager, который немного привели в порядок и сделали чуть более гибким.

Визуально всё выглядело точно так же. Такой же сервис:

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

Сам же запуск задач с течением времени не изменился.

Плюсы:
API, аналогичное JobScheduler;
доступно начиная с API 9.

Минусы:
необходимо иметь Google Play Services;
легко ошибиться.

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

Google знает об этом, но эти задачи несколько лет остаются открытыми.

Android 7. Nougat

Android Job by Evernote


В итоге сообщество не выдержало, и появилось самописное решение в виде библиотеки от Evernote. Оно было не единственное, но именно решение от Evernote смогло зарекомендовать себя и «выбилось в люди».

В архитектурном плане эта библиотека была удобнее своих предшественников.
Появилась сущность, отвечающая за создание задач. В случае с JobScheduler они создавались через reflection.

Имеется отдельный класс, который является самой задачей. В JobScheduler это всё было свалено в switch внутри onStartJob.

Запуск задач идентичен, но кроме унаследованных событий Evernote ещё добавил и свои, такие как запуск ежедневных задач, уникальные задачи, запуск в рамках окна.

Плюсы:
удобное API;
поддерживается на всех версиях;
не нужны Google Play Services.

Минусы:
стороннее решение.

Ребята активно поддерживали свою библиотеку. Хотя было довольно много критичных проблем, она работала на всех версиях и на всех девайсах. В итоге в прошлом году наша Android-команда выбрала решение именно от Evernote, так как библиотеки от Google срезают большой пласт девайсов, которые они не могут поддержать.
Внутри себя же она работала на решениях от Google, в крайних случаях — с AlarmManager.

Background Execution Limits


Вернёмся к нашим ограничениям. С приходом нового Android пришли и новые оптимизации. Ребята из Google нашли другую проблему. В этот раз всё дело оказалось в сервисах и бродкастах (да, ничего нового).

  • startService если приложения в фоне
  • implicit broadcast в манифесте

Во-первых, было запрещено запускать сервисы из фона. В «рамках закона» остались только foreground services. Сервисы теперь, можно сказать, deprecated.
Второе ограничение — всё те же бродкасты. В этот раз стала запрещена регистрация ВСЕХ неявных бродкастов в манифесте. Неявный бродкаст — это бродкаст, который предназначается не только нашему приложению. Например, есть Action ACTION_PACKAGE_REPLACED, а есть ACTION_MY_PACKAGE_REPLACED. Так вот, первый — это неявный.

Но любой бродкаст по-прежнему можно зарегистрировать через Context.registerBroadcast.

WorkManager


На этом оптимизации пока прекратились. Возможно, устройства стали работать быстро и бережно в плане энергопотребления; возможно, пользователи стали меньше жаловаться на это.
В Android 9 разработчики фреймворка основательно подошли к инструменту для запуска задач. В попытке решить все насущные проблемы, на Google I/O была представлена библиотека для запуска бэкграунд-задач WorkManager.

Читайте также:  Андроид наушники значок как отключить

Google последнее время пытается сформировать своё видение архитектуры Android-приложения и даёт разработчикам инструменты, необходимые для этого. Так появились архитектурные компоненты с LiveData, ViewModel и Room. WorkManager выглядит как разумное дополнение их подхода и парадигмы.

Если же говорить про то, как устроен WorkManager внутри, то никакого технологического прорыва в нём нет. По сути это обёртка уже существующих решений: JobScheduler, FirebaseJobDispatcher и AlarmManager.

Код выбора довольно прост. Но надо заметить, что JobScheduler доступен начиная с API 21, но используют его только с API 23, так как первые версии были довольно нестабильные.

Если версия ниже 23, то через reflection пробуем найти FirebaseJobDispatcher, в противном случае используем AlarmManager.

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

  • Worker — логика работы;
  • WorkRequest — логика запуска задачи;
  • WorkRequest.Builder — параметры;
  • Constrains — условия;
  • WorkManager — менеджер, который управляет задачами;
  • WorkStatus — статус задачи.

Условия для запуска наследовались от JobScheduler.
Можно отметить, что триггер на изменение URI появился только с API 23. К тому же можно подписаться на изменение не только определённого URI, но и всех вложенных в него с помощью флага в методе.

Если говорить о нас, то ещё на этапе альфы было решено перейти на WorkManager.
Причин для этого несколько. В Evernote есть пара критичных багов, которые разработчики библиотеки обещают поправить с переходом на версию с интегрированным WorkManager. Да и сами они соглашаются, что решение от Google сводит на нет плюсы Evernote. К тому же это решение хорошо вписывается в нашу архитектуру, так как мы используем Architecture Components.

Далее хотелось бы на простом примере показать, в каком виде мы стараемся использовать этот подход. При этом не сильно критично, WorkManager у вас или JobScheduler.

Посмотрим на пример с очень простым кейсом: клик по republish или like.

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

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

Далее покажу пример того, как это выглядит у нас.

JobRunner содержит логику запуска задач. В его методах описывается конфигурация задач и передаются параметры.

Сама задача в рамках WorkManager выглядит следующим образом: берём id из параметров и вызываем метод на сервере, чтобы поставить лайк на этот контент.

У нас есть базовый класс, который содержит следующую логику:

Во-первых, он позволяет немного уйти от явного знания о Worker. Также он содержит логику внедрения зависимостей через WorkerInjector.

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

Interactor — это сущность, которую дёргает ViewController, чтобы инициировать прохождение сценария (в данном случае —поставить лайк). Мы отмечаем локально контент как «залайканный» и отправляем задачу на выполнение. Если задача происходит неуспешно, то лайк снимается.

Мы используем Architecture Components от Google: ViewModel и LiveData. Так выглядит наша ViewModel. Здесь мы связываем обновление объекта в DAO со статусом лайка.

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

И это практически весь код, необходимый нам. Осталось дописать поведение самой View с лайком и реализацию вашего DAO; если вы используете Room, то просто прописать поля в объекте. Выглядит довольно просто и эффективно.

Если подводить итоги


JobScheduler, GCM Network Manager, FirebaseJobDispatcher:

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

Android Job by Evernote:

  • внутри будут использовать WorkManager;
  • критичные баги размываются между решениями.

WorkManager:

  • API LEVEL 9+;
  • не зависит от Google Play Services;
  • Chaining/InputMergers;
  • реактивный подход;
  • поддержка от Google (хочется в это верить).

Источник

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