IntentService
Класс IntentService является подклассом класса Service. Он используется, если надо выполнять какие-то тяжёлые задачи с намерениями, которые могут выполняться асинхронно. Принцип работы этого вида сервиса прост. Он создаёт новый поток для своей работы, затем мониторит все входящие намерения и отправляет их на обработку в этот поток. Далее в коде вы определяете, как обработать Intent. Вам не нужно запускать AsyncTask и управлять тяжёлыми задачами, сервис сам справится. Вы можете отправить данные обратно в приложение через широковещательное сообщение и принять сообщение через широковещательный приёмник.
Иными словами, приложение посылает в сервис данные через метод startService(), в которых передаёт намерения. IntentService принимает эти вызовы, берёт намерения последовательно и отправляет их в очередь на обработку. И далее они поочерёдно обрабатываются в отдельном потоке методом onHandleIntent() по одному за раз. Когда последний Intent из очереди будет обработан, сервис сам завершит свою работу.
Во многих случаях использование IntentService проще, чем AsyncTask или Thread.
Напишем код для основной активности, в которой осуществим три вызова сервиса через метод startService(). Переменная time – это время паузы, которую будем делать в сервисе, а task – просто метка, чтобы отличать вызовы. Для этого создаётся намерение с указанием нужной службы, а в дополнительных параметрах передаются данные.
В коде встречается вызов класса MyIntentService. Создадим его.
В классе необходимо создать конструктор, в котором вызываем конструктор суперкласса и указываем какое-нибудь имя, которое будет использовано для наименования потока.
В методе onHandleIntent() обрабатываем намерения. Достаём из них значения переменных time и task, запускаем паузу на time секунд и выводим в лог значения label в начале и в конце.
Не забываем прописать сервис в манифесте в секции application:
В итоге, при запуске в логах видим следующее:
Сервис создался, вызовы выполнились по очереди и сервис завершил работу.
Усложним задачу. Сейчас мы просто вывели результаты в журнал, а сама активность не получила уведомления. Создадим отдельное намерение и отправим его через метод sendBroadcast().
Теперь в основной активности необходимо зарегистрировать свой BroadcastReceiver и принять сообщение от сервиса:
В данном примере мы возвращаем результат после выполнения всех задач и выводим в одной текстовой метке. В методе onHandleIntent() вы можете выполнять тяжёлые задачи. Так как они выполняются в другом потоке, то ваша основная активность остаётся отзывчивой на действия пользователей. Как только сервис завершит обработку данных, то сработает отправка широковещательного сообщения обратно приложению через метод sendBroadcast(). И вам его надо только принять и обработать.
Не забывайте снимать регистрацию приёмника через метод unregisterReceiver() (рекомендуется в методах onPause() или onDestroy() в нашем примере).
Промежуточные результаты
Дополним программу и будем посылать в активность промежуточные результаты, которые будут обновлять состояние индикатора прогресса. Добавим индикатор на экран.
Добавим в класс службы дополнительный код.
В активности следует зарегистрировать ещё один широковещательный приёмник. Сервис в цикле создаёт промежуточные данные и отсылает его активности. Активность принимает данные через приёмник и обновляет состояние индикатора.
Запустив пример, вы увидите сначала работу индикатора прогресса, а потом выведется текст. Также промежуточные данные можно отсылать в уведомления. Добавим код в существующий код:
Если вы запустите код, то увидите, что будет обновляться не только индикатор на главном экране приложения, но и данные в уведомлениях.
Запуск и остановка службы
В примерах служба запускалась одновременно с запуском приложения. Перенесём код в кнопку. А также добавим вторую кнопку для остановки службы. При этом будем отслеживать количество запущенных служб.
Код для активности.
Вызываем Toast
Вызвать Toast в методе onHandleIntent() напрямую не получится, сообщение не появляется. Следует создать отдельный поток. Чтобы выполнение проходило в основном потоке, объект Handler должен быть создан в методе, выполняемом в основном потоке. Метод onHandleIntent() не подходит, так как он выполняется в фоновом потоке. Вместо этого воспользуемся методом onStartCommand(), который вызывается каждый раз при запуске службы через намерение. Метод onStartCommand() выполняется в основном потоке и отрабатывает до метода onHandleIntent(). Если создать объект Handler в методе onStartCommand(), то его можно будет использовать для передачи кода в основной поток в методе onHandleIntent():
Источник
Полный список
— изучаем IntentService
— включаем режим Foreground для сервиса
— помещаем сервис в автозагрузку
Строили мы, строили, и, наконец, построили. Урок номер 100, с чем всех нас и поздравляю )
В этом уроке рассмотрим еще несколько полезных вещей про сервисы. Выносить каждую из них в отдельный урок я не стал, вполне можно в одном все рассмотреть. Проекты здесь тоже создавать не будем, чтобы урок не получился слишком громоздким. Я просто приведу некоторые куски кода и скрины для наглядности своих рассуждений. А если у вас будет желание, вы по этим наработкам сами можете создать проекты-примеры.
IntentService
Это подкласс обычного Service. Он используется, если вам в сервисе надо выполнять какие-то тяжелые задачи, и вы не хотите сами возиться с асинхронностью. Принцип работы этого вида сервиса прост. Он создает новый поток для своей работы. Затем берет все Intent пришедшие ему в onStartCommand и отправляет их на обработку в этот поток. Как именно обрабатываются Intent – зависит от нас, т.к. мы сами кодим это в методе onHandleIntent.
Т.е. приложение сыпет в сервис вызовами startService, в которых передает Intent-ы. IntentService принимает эти вызовы в onStartCommand, берет Intent-ы и отправляет их в очередь на обработку. И далее они поочередно обрабатываются в отдельном потоке методом onHandleIntent. Когда последний Intent из очереди обработан, сервис сам завершает свою работу.
В приложении делаем три вызова:
Где time – это время паузы, которую будем делать в сервисе, а label – просто метка, чтобы отличать вызовы.
Здесь необходим конструктор, в котором вызываем конструктор супер-класса и указываем какое-нить имя. Оно будет использовано для наименования потока.
В методе onHandleIntent кодим обработку Intent-ов. Достаем из них time и label, запускаем паузу на time секунд и выводим в лог label в начале и в конце.
В итоге, при запуске в логах видим:
11:07:37.880: D/myLogs(4137): onCreate
11:07:37.880: D/myLogs(4137): onHandleIntent start Call 1
11:07:40.880: D/myLogs(4137): onHandleIntent end Call 1
11:07:40.880: D/myLogs(4137): onHandleIntent start Call 2
11:07:41.880: D/myLogs(4137): onHandleIntent end Call 2
11:07:41.880: D/myLogs(4137): onHandleIntent start Call 3
11:07:45.890: D/myLogs(4137): onHandleIntent end Call 3
11:07:45.890: D/myLogs(4137): onDestroy
Сервис создался, вызовы выполнились по очереди и сервис завершил работу. От нас понадобилось только накодить обработку.
Foreground
Вы можете сказать системе, что ваш сервис очень важен для пользователя и его нельзя грохать при нехватке памяти. Это актуально, например, для музыкального плеера. В статус-бар при этом будет помещено уведомление.
На вход он принимает те же параметры, что и NotificationManager.notify – ID и Notification.
Т.е. вы создаете уведомление, назначаете ему ID и передаете это в startForeground. Сервис переходит в режим IDDQD :), а в статус-баре появилось уведомление.
Оно появилось в разделе для постоянных уведомлений (Ongoing).
Метод stopForeground (boolean removeNotification) — возвращает сервису способность быть убитым системой в случае острой нехватки памяти. А на вход он принимает boolean-значение – удалять уведомление из статус-бара или нет.
Уведомление также пропадет, когда сервис будет остановлен.
Эти методы работают, начиная с Android 2.0. Пример реализации для более ранних версий есть в хелпе.
Напомню, что уведомления мы научились создавать на прошлом уроке.
Автозагрузка
Сервисы для получения погоды или почты имеет смысл помещать в автозагрузку. Для этого нам надо создать BroadcastReceiver, настроить его IntentFilter на Action = android.intent.action.BOOT_COMPLETED, и добавить права android.permission.RECEIVE_BOOT_COMPLETED. Этот BroadcastReceiver будет вызван системой при старте системы и в нем мы кодим запуск сервиса.
Допустим, есть проект с сервисом MyService.
Создаем в проекте класс MyBroadReceiv
В манифесте добавляем его как Receiver и настраиваем фильтр
Добавляем права на получение сообщения о загрузке
Инсталлим проект на AVD. Закрываем AVD. Запускаем через меню в Eclipse: Window > AVD Manager. Находим там наш эмулятор и запускаем вручную.
Когда он запустился, смотрим логи
onReceive android.intent.action.BOOT_COMPLETED
MyService onCreate
MyService onStartCommand
Сработал BroadcastReceiver и запустил сервис.
Если после запуска AVD логи не отображаются, то откройте DDMS и во вкладке Devices явно выберите ваш AVD.
P.S. Я уже писал об этом, но напишу еще раз. Последующие уроки будут выходить по более свободному графику. Следите за обновлениями.
На следующем уроке:
— создаем свой ContentProvider
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Источник
Сервис против IntentService на платформе Android
Я ищу пример того, что может быть сделано с помощью, IntentService что не может быть сделано с Service (и наоборот)?
Я также считаю, что он IntentService работает в другом потоке, а Service нет. Итак, насколько я вижу, запуск службы в своем собственном потоке похож на запуск IntentService . Это верно?
Теджас Лагванкар написал хороший пост на эту тему. Ниже приведены некоторые ключевые различия между Service и IntentService.
Когда использовать?
Сервис может быть использован в задачах, не имеющих пользовательского интерфейса, но не должно быть слишком длинным. Если вам нужно выполнять длинные задачи, вы должны использовать потоки в Сервисе.
IntentService можно использовать в длинных задачах , как правило, без связи с основным потоком. Если требуется связь, можно использовать обработчик основного потока или широковещательные намерения. Другой случай использования — когда требуются обратные вызовы (задачи, инициируемые намерением).
Как вызвать?
Служба запускается с помощью вызова метода startService() .
IntentService срабатывает используя Намерение, создается новый рабочий поток и метод onHandleIntent() вызывается в этом потоке.
Запущен из
- Обслуживание и IntentService могут быть вызваны из любого потока, активности или другого компонента приложения.
Работает на
Служба работает в фоновом режиме , но он работает на главном потоке приложения.
IntentService работает на отдельном потоке.
Ограничения / Недостатки
Служба может блокировать главный поток приложения.
IntentService не может выполнять задачи параллельно. Следовательно, все последовательные намерения будут помещены в очередь сообщений для рабочего потока и будут выполняться последовательно.
Когда остановиться?
Если вы внедряете Сервис , вы обязаны остановить сервис после завершения его работы, позвонив по телефону stopSelf() или stopService() . (Если вы хотите предоставить только привязку, вам не нужно реализовывать этот метод).
IntentService останавливает службу после того, как все запросы начала были обработаны, так что вы никогда не должны вызовом stopSelf() .
Если кто-то может показать мне пример чего-то, что может быть сделано с помощью IntentService и не может быть сделано с помощью Service и наоборот.
По определению это невозможно. IntentService это подкласс Service , написанный на Java. Следовательно, все, что IntentService делает, Service может сделать, включая соответствующие биты кода, который IntentService использует.
Запуск службы с собственным потоком подобен запуску IntentService. Это не?
Три основные особенности IntentService :
автоматическая очередь Intent s доставляется onStartCommand() , поэтому, если один Intent обрабатывается onHandleIntent() в фоновом потоке, другие команды выстраиваются в очередь в ожидании своей очереди
автоматическое отключение IntentService через вызов stopSelf() , когда очередь пуста
Все это может быть реализовано Service без расширения IntentService .
обслуживание
- Вызвать startService()
- Срабатывает от любого Thread
- Работает на Main Thread
- Может блокировать основной поток (пользовательский интерфейс). Всегда используйте поток внутри службы для долгой задачи
- Как только задача выполнена, мы обязаны прекратить обслуживание, позвонив stopSelf() или stopService()
IntentService
- Он выполняет длинную задачу, обычно без связи с основным потоком, если связь необходима, то это делается Handler или BroadcastReceiver
- Вызвать через Intent
- Запущен из Main Thread
- Работает в отдельном потоке
- Невозможно запустить задачу параллельно, и несколько целей помещаются в очередь в одном рабочем потоке.
Не изобретай велосипед
IntentService расширяет класс Service, что явно означает, что IntentService сделано специально для же цели.
Так в чем же цель?
`Цель IntentService — облегчить нашу работу для выполнения фоновых задач, даже не беспокоясь о
Создание рабочего потока
Очередь обработки нескольких запросов по одному ( Threading )
Таким образом, НЕТ , Service может выполнить любую задачу, которая IntentService будет делать. Если ваши требования подпадают под вышеупомянутые критерии, вам не нужно писать эту логику в Service классе. Так что не изобретай велосипед, потому что IntentService это изобретенное колесо.
«Главное» отличие
Служба работает в потоке пользовательского интерфейса, а IntentService — в отдельном потоке.
Когда вы используете IntentService?
Если вы хотите выполнить несколько фоновых задач одну за другой, которая выходит за рамки действия, тогда IntentService все идеально.
Как IntentService сделано из Service
Обычный сервис работает в потоке пользовательского интерфейса (любой тип компонента Android по умолчанию работает в потоке пользовательского интерфейса, например Activity : BroadcastReceiver , ContentProvider и Service ). Если вам нужно выполнить какую-то работу, которая может занять некоторое время, то вы должны создать поток. В случае нескольких запросов вам придется иметь дело с synchronization . IntentService дается некоторая реализация по умолчанию, которая выполняет эти задачи за вас.
По словам разработчика
IntentService создает рабочий поток
IntentService создает рабочую очередь, которая отправляет запрос onHandleIntent() методу один за другим
Добавление баллов к принятому ответу:
Смотрите использование IntentService в Android API. например:
Чтобы создать компонент IntentService для вашего приложения, определите класс, который расширяет IntentService, и в нем определите метод, который переопределяет onHandleIntent ().
Также см. Исходный код IntentService, его конструктор и методы жизненного цикла, такие как onStartCommand .
Совместное использование AsyncTask является одним из лучших подходов для многих случаев, когда полезная нагрузка невелика. или просто создайте класс, расширяющий IntentSerivce. Начиная с версии 4.0 Android, все сетевые операции должны выполняться в фоновом режиме, иначе сборка / сборка приложения завершится неудачно. отдельный поток от пользовательского интерфейса. Класс AsyncTask предоставляет один из самых простых способов запуска новой задачи из потока пользовательского интерфейса. Более подробное обсуждение этой темы смотрите в блоге.
IntentService — это базовый класс для служб, которые обрабатывают асинхронные запросы (выраженные как Intents) по требованию. Клиенты отправляют запросы через вызовы startService (Intent); служба запускается по мере необходимости, обрабатывает каждое намерение, в свою очередь, используя рабочий поток, и останавливается, когда заканчивается его работа.
Шаблон проектирования, используемый в IntentService
: Этот шаблон «обработчик рабочей очереди» обычно используется для выгрузки задач из основного потока приложения. Класс IntentService существует, чтобы упростить этот шаблон и позаботиться о механике. Чтобы использовать его, расширьте IntentService и внедрите onHandleIntent (Intent). IntentService получит Intents, запустит рабочий поток и остановит службу соответствующим образом.
Все запросы обрабатываются в одном рабочем потоке — они могут занимать столько времени, сколько необходимо (и не будет блокировать основной цикл приложения), но одновременно обрабатывается только один запрос.
Класс IntentService предоставляет простую структуру для выполнения операции в одном фоновом потоке. Это позволяет ему обрабатывать длительные операции, не влияя на отзывчивость вашего пользовательского интерфейса. Кроме того, IntentService не подвержен влиянию большинства событий жизненного цикла пользовательского интерфейса, поэтому он продолжает работать при обстоятельствах, приводящих к отключению AsyncTask.
IntentService имеет несколько ограничений:
Он не может напрямую взаимодействовать с вашим пользовательским интерфейсом. Чтобы поместить его результаты в пользовательский интерфейс, вы должны отправить их в Activity. Рабочие запросы выполняются последовательно. Если операция выполняется в IntentService, и вы отправляете ему еще один запрос, запрос ожидает завершения первой операции. Операция, выполняемая на IntentService, не может быть прервана. Однако в большинстве случаев
IntentService является предпочтительным способом для простых фоновых операций
Есть библиотека volley-library для разработки приложений для Android. . Исходный код доступен для всех на GitHub.
Официальная документация для Android по рекомендациям для фоновых заданий : помогает лучше понять намерение службы, потока, обработчика, службы. а также выполнение сетевых операций
Источник