- Broadcast (Широковещательные сообщения)
- Передача сообщений
- Приёмники широковещательных сообщений
- Периодическое срабатывание каждую минуту
- TIME_TICK на Kotlin
- Автостарт Activity или Service при загрузке (перезагрузке) девайса
- Следим за питанием
- Android для начинающих: Понимание Android-бродкастов
- 1. Создание трансляции
- 2. Получение трансляций
- 3. Передача системных трансляций
- 4. Работа с локальными трансляциями
- 5. Использование EventBus
- Заключение
Broadcast (Широковещательные сообщения)
В Android существует понятие широковещательных сообщений, которые можно отправлять или принимать. Оба процесса между собой не связаны и их можно использовать по отдельности.
Передача сообщений
Для начала научимся отправлять сообщения. В одном из уроков мы учились запускать другую активность с помощью намерения Intent. Но намерения можно использовать для отправки сообщений, предназначенные не какому-то отдельному приложению, объекту или компоненту, а всем. И любая программа, оборудованная специальным приёмником, может поймать это сообщение и предпринять свои шаги на основе полученной информации.
Для понимания, представьте, что радистка Кэт отправляет сообщение: «Срочно пришлите кота! Хочу быть сильной независимой женщиной. А ваш Штирлиц — фашист!». Возможно в этом сообщении содержится шифровка, что нужно прислать жену, столик для жены разведчика в кафе заказан, а Штирлиц — козёл! Но это не важно для нашего урока.
Любой человек, имеющий специальный оборудованный радиоприёмник, может принять это сообщение. Так же поступают и программы. Они обзаводятся приёмниками и прослушивают определённый тип сообщений.
Сообщения может создавать сама система, а также ваша программа и чужие программы.
Передача сообщений весьма проста в реализации. В вашем приложении необходимо создать сообщение, которое вы хотите передать. Установите при необходимости поля action, data и category (действие, данные и категорию) вашего сообщения и путь, который позволяет приёмникам широковещательных сообщений точно определять «своё» сообщение. В этом сообщении строка действия ACTION должна быть уникальной, чтобы идентифицировать передаваемое действие. В таких случаях создают строку-идентификатор действия по правилам именования пакетов Java. Например, для обнаружения кота в большом здании:
Далее вы создаёте объект Intent, загружаете в него нужную информацию и вызываете метод sendBroadcast(), передав ему в качестве параметра созданный объект Intent. Дополнительные данные можно использовать в extras как необязательные параметры.
Виртуальный код для обнаружения кота:
В этом примере мы создали намерение с уникальной строкой, передали дополнительные данные (имя кота и его координаты), отправили сообщение. Другое приложение, связанное с картами, может принять сообщение и показать кота на карте.
Существуют также родственные методы sendStickyBroadcast() и sendOrderedBroadcast().
Для старых устройств этого было вполне достаточно, но начиная с Android 3.0, в целях безопасности сообщения будут игнорироваться остановленными приложениями, чтобы они не запускались. Поэтому следует добавлять дополнительный флаг, разрешающий запуск активности.
Мы напишем простой пример, который будет отправлять сообщения и также создадим приёмник для его получения. О приёмнике мы поговорим подробно во второй части урока. А пока получим первое представление о нём.
Создайте новый проект и разместите на экране кнопку с надписью «Отправить сообщение». Присвойте атрибуту onClick название метода, в котором будет происходит отправка широковещательного сообщения.
В классе активности создаём уникальную строку и реализуем метод для щелчка кнопки. Также добавим дополнительные данные — первую часть послания радистки.
Запустив пример, вы можете нажать на кнопку и отправлять сообщение. Только ваше сообщение уйдёт в никуда, так как ни одно приложение не оборудовано приёмником для него. Исправим ситуацию и создадим приёмник в своём приложении. Мы будем сами принимать свои же сообщения.
Приёмник представляет собой обычный Java-класс на основе BroadcastReceiver. Вы можете создать вручную класс и наполнить его необходимыми методами. Раньше так и поступали. Но в студии есть готовый шаблон, который поможет немного сэкономить время.
Щёлкаем правой кнопкой мыши на названии пакета и выбираем New | Other | Broadcast Receiver
В диалоговом окне задаём имя приёмника, остальные настройки оставляем без изменений.
Студия создаст изменения в двух местах. Во-первых, будет создан класс MessageReceiver:
Во-вторых, в манифесте будет добавлен новый блок.
В него следует добавить фильтр, по которому он будет ловить сообщения.
Вернёмся в класс приёмника и модифицируем метод onReceive().
Снова запустим пример и ещё раз отправим сообщение. Так как наше приложение теперь оборудовано не только передатчиком, но и приёмником, то оно должно уловить сообщение и показать его нам.
Вы можете создать другое приложение с приёмником, чтобы одно приложение посылало сообщение, а другое принимало.
Приёмники широковещательных сообщений
Вот плавно мы перешли к приёмникам широковещательных сообщений. На самом деле вам не так часто придётся рассылать сообщения, гораздо чаще встречается потребность принимать сообщения. В первую очередь, сообщения от системы. Примерами таких сообщений могут быть:
- Низкий заряд батареи
- Нажатие на кнопку камеры
- Установка нового приложения
Приёмник можно создать двумя способами — через манифест (мы использовали этот способ в примере) и программно через метод registerReceiver(). Между двумя способами есть существенная разница. Приёмник, заданный в манифесте, известен системе, которая сканирует файлы манифеста всех установленных приложений. Поэтому, даже если ваше приложение не запущено, оно всё равно сможет отреагировать на поступающее сообщение.
Приёмник, созданный программно, может работать только в том случае, когда активность вашего приложения активна. Казалось, это является недостатком и нет смысла использовать такой подход. Но всё не так просто. Некоторые системные сообщения могут обрабатываться только приёмниками, созданными программно. И в этом есть свой резон. Например, если ваше приложение не запущено, ему нет смысла принимать сообщения о заряде батареи. Иначе заряд батареи будет расходоваться ещё быстрее при лишней бесполезной работе. Информацию о заряде батареи ваше приложение может получить, когда в этом есть необходимость. Следует сверяться с документацией, какой вид приёмника следует использовать.
При программной регистрации приёмника мы можем также снять регистрацию, когда больше не нуждаемся в нём с помощью метода unregisterBroadcastReceiver().
Периодическое срабатывание каждую минуту
Рассмотрим пример периодического срабатывания приёмника каждую минуту с помощью системного намерения android.intent.action.TIME_TICK. Приёмник будет создан программно. Добавим на экран активности две кнопки для регистрации и отмены регистрации широковещательного сообщения.
Создадим вручную новый класс TimeBroadcastReceiver, наследующий от BroadcastReceiver:
Вы можете создать класс приёмника и через шаблон, как мы это сделали в предыдущем примере. Но в этом случае удалите запись о нём в манифесте, так как нам он не понадобится. Но если вы забудете сделать это, то ничего страшного не произойдёт, так как там не прописаны фильтры.
Откроем код главной активности и зарегистрируем (а также снимем регистрацию) приёмник:
Запускаем проект и нажимаем на первую кнопку, чтобы включить рассылку широковещательного сообщения. Теперь каждую минуту будет срабатывать запуск всплывающего сообщения с текущим временем. Даже если вы переключитесь на другое приложение, то всё равно будете видеть сообщения.
Это один из примеров, когда приёмник следует регистрировать программно. Я видел часто на форумах вопросы, почему не работает данное намерение android.intent.action.TIME_TICK. А не надо было его регистрировать в манифесте.
В нашем примере мы устанавливали и снимали регистрацию через нажатия кнопок. Обычно включают регистрацию в методе onResume(), а снимают регистрацию в методе onPause().
Необходимо помнить, что программная регистрация широковещательного сообщения создаётся в основном потоке приложения и это может послужить источником ошибок, если операции в BroadcastReceiver занимают длительное время. Как вариант, используйте сервисы. Почитайте на эту тему статью (en).
TIME_TICK на Kotlin
Напишем похожий пример на Kotlin. Разместите на экране TextView, в котором будет отображаться время. Код для активности ниже. Обратите внимание, что мы не создаём отдельный класс для BroadcastReceiver, включаем регистрацию в onResume() и снимаем регистрацию в onPause().
Автостарт Activity или Service при загрузке (перезагрузке) девайса
Ещё один полезный пример, который часто используется приложениями.
Если ваше приложение (сервис) должно запускаться сразу после перезагрузки устройства, то используйте намерение android.intent.action.BOOT_COMPLETED:
Мы создали отдельный класс для широковещательного сообщения. Также нужно создать разрешение и зарегистрировать приёмник в манифесте.
Следим за питанием
Нет, речь пойдёт не о правильном питании кота. Имеется в виду питание от электричества. Если ваше устройство отключить от зарядки, то система оповещает об этом событии через широковещательное намерение android.intent.action.ACTION_POWER_DISCONNECTED.
Не станем заводить новый приёмник, а откроем манифест и добавим дополнительный фильтр к приёмнику сообщений от радистки Кэт.
А в классе MessageReceiver добавим код для метода.
Пример нужно проверять на реальном устройстве. Подключите устройство к питанию, а затем выдерните кабель. На экране появится сообщение.
Источник
Android для начинающих: Понимание Android-бродкастов
Большинство из нас слишком хорошо знакомы с объявлениями в общественных местах. Это громкие сообщения, которые предназначены для информирования больших групп людей о чем-то важном. Приложениям Android также приходится иметь дело с объявлениями иногда это объявления, создаваемые либо другими приложениями, либо самой операционной системой Android. Такие объявления называются трансляциями, и они рассматриваются как важная форма асинхронной межпроцессной коммуникации на платформе Android.
В этом уроке я покажу вам, как создавать, отправлять и получать как локальные, так и общесистемные трансляции. Я также покажу вам, как использовать стороннюю библиотеку EventBus, которая может служить альтернативой локальным трансляциям.
1. Создание трансляции
Android-трансляции отправляются в виде объектов Intent . Поэтому перед созданием трансляции вы должны создать объект Intent . В этой серии есть подробный учебник о намерениях. Если вы еще не прочитали его, сейчас самое подходящее для этого время.
Каждое намерение, которое вы отправляете в виде трансляции, должно иметь название действия. Хотя имя действия может быть любой строкой, я рекомендую вам всегда указывать имя пакета вашего приложения, чтобы избежать конфликтов с трансляциями от других приложений.
Следующий фрагмент кода показывает, как создать новое намерение с именем действия com.tutsplus.my.first.broadcast:
Чтобы отправить намерение в эфир, все, что вам нужно сделать, это вызвать метод sendBroadcast() и передать объект Intent в качестве аргумента.
Обратите внимание, что метод sendBroadcast() создает глобальную трансляцию, которая может быть получена не только вашим приложением, но и любым другим приложением, установленным на устройстве пользователя.
2. Получение трансляций
Чтобы иметь возможность принимать трансляцию, ваше приложение должно иметь надлежащим образом настроенный приемник трансляций. Вы можете создать такой приемник, расширив абстрактный класс BroadcastReceiver и переопределив его метод onReceive() . Например, вот как вы создаете приемник, который печатает сообщение каждый раз, когда он получает трансляцию:
Приемник работает только в том случае, если он зарегистрирован. Самый простой способ сделать это — объявить его в файле манифеста проекта с помощью тега receiver .
Кроме того, внутри объявления приемника вы должны включать теги intent-filter , в которых указываются имена действий, в которых заинтересован широковещательный приемник.
Следующий фрагмент кода регистрирует MyBroadcastReceiver и настраивает его для ответа на действие com.tutsplus.my.first.broadcast:
3. Передача системных трансляций
Операционная система Android выпускает несколько глобальных трансляций. Большинство из них содержат ценную информацию об изменениях в состоянии Android-устройства. Например, каждый раз, когда пользователь помещает новый исходящий вызов, выдается трансляция android.intent.action.NEW_OUTGOING_CALL . Аналогично, каждый раз, когда пользователь включает или выключает режим полета, выдается трансляция android.intent.action.AIRPLANE_MODE .
Получение системной трансляции — это как получение обычных трансляций. Однако большинство системных трансляций содержат дополнительную информацию в виде дополнительных функций. Вы можете получить все эти дополнительные функции как объект Bundle, вызвав метод getExtras (). Например, намерение трансляция android.intent.action.AIRPLANE_MODE всегда содержит дополнение state , которое является логическим значением, которое определяет, включен или выключен режим полета.
В следующем фрагменте кода показано, как регистрировать значение дополнительное значение state :
Обратите внимание, что приведенный выше код будет работать только в том случае, если вещательный приемник зарегистрирован с помощью следующего фильтра намерений:
4. Работа с локальными трансляциями
По очевидным причинам глобальные трансляции никогда не должны содержать конфиденциальную информацию. Тем не менее, вы можете передавать такую информацию локально, используя класс LocalBroadcastManager , который входит в состав Android Support Library.
Если вы используете последнюю версию Android Studio, вам не придется вручную добавлять зависимость для библиотеки поддержки Android. Однако, если вы хотите реализовать локальные трансляции в старом проекте, убедитесь, что следующая строка присутствует в файле build.gradle модуля app:
Чтобы создать новый экземпляр класса LocalBroadcastManager , вы должны вызвать его метод getInstance() и передать свою деятельность или сервис в качестве контекста. Например, вот как создать экземпляр внутри действия под названием MyActivity :
Теперь вы можете отправлять локальные трансляции, используя метод sendBroadcast() класса LocalBroadcastManager . Следующий фрагмент кода создает новое намерение, название действия которого — my-local-broadcast , и отправляет его в качестве локальной трансляции:
Получение местной трансляции выглядит несколько сложнее. Локальный приемник не должен быть зарегистрирован в файле манифеста проекта. Вместо этого он должен регистрироваться динамически с использованием метода registerReceiver() класса LocalBroadcastManager . В дополнение к экземпляру приемника для метода registerReceiver() требуется объект IntentFilter , определяющий имя действия, на которое должен реагировать приемник.
Вот как вы могли бы создать и зарегистрировать приемник, который может реагировать на действие my-local-broadcast :
Динамически зарегистрированные получатели должны быть отсоединены, когда они больше не нужны. Для этого вы должны использовать метод unregisterReceiver() класса LocalBroadcastManager .
5. Использование EventBus
Если вы считаете, что местные трансляции и намерения не дают вам всю необходимую гибкость, вам следует рассмотреть возможность использования EventBus — сторонней библиотеки, которая позволяет асинхронно отправлять данные из одного компонента вашего приложения в другой. На мой взгляд, API EventBus очень интуитивно понятен и краток.
Чтобы включить EventBus в свой проект, добавьте следующую compile зависимость в файл build.gradle вашего модуля app:
Вместо объектов Intent EventBus позволяет отправлять и получать объекты любого класса Java. Например, экземпляры следующего класса могут быть легко использованы с EventBus:
EventBus реализует шаблон publisher-subscriber и создает центральную шину, доступную для всех компонентов вашего приложения. Поэтому компонент, который должен отправлять объекты, должен просто публиковать объекты на шине. Компонент, который заинтересован в получении этих объектов, должен зарегистрироваться как абонент шины.
Самый быстрый способ получить экземпляр центральной шины — использовать метод getDefault() класса EventBus .
Чтобы опубликовать объект, все, что вам нужно сделать, это вызвать метод post() для шины. Например, вот как вы могли бы опубликовать экземпляр класса MyMessage :
Компонент приложения, такой как активность или услуга, может регистрироваться как абонент, вызывая метод register() шины. Следующий пример кода регистрирует услугу MyService :
Компонент, который действует как подписчик, должен также иметь метод подписки, который является любым методом, который имеет аннотацию @Subscribe . Методы подписчиков ведут себя подобно обработчикам событий и автоматически вызываются каждый раз, когда на шине доступны новые объекты.
В следующем фрагменте кода показано, как создать очень простой метод подписки, который автоматически вызывается каждый раз, когда на шине доступен новый экземпляр класса MyMessage :
Заключение
В этом уроке вы узнали, как отправлять информацию с одного прикладного компонента на другой, используя глобальные и локальные трансляции. Вы также узнали, как использовать очень популярную библиотеку EventBus для общения внутри приложения. Поскольку трансляции имеют очень низкие накладные расходы, вы можете отправлять максимально часто. Фактически, система Android генерирует новую трансляцию android.intent.action.TIME_TICK каждую минуту.
Чтобы узнать больше о приемниках и трансляциях Android, вы можете обратиться к документации классов BroadcastReceiver и Intent.
Источник