Приложения не живут в вакууме — вокруг постоянно что-то происходит. Телефон разряжается, подключаются наушники, меняется сеть с Wi-Fi на мобильный интернет. Чтобы программа могла на это реагировать, в Android придумали механизм широковещательных сообщений. В этом уроке мы разберём, как с помощью Kotlin создать приёмник таких событий прямо в Android Studio и сделать приложение умнее, без постоянных проверок в фоне.
Что такое BroadcastReceiver
BroadcastReceiver — это компонент, который слушает системные оповещения и выполняет ваш код, когда происходит что-то важное. Представьте почтальона, который приносит письма. Система отправляет «письма» с новостями: батарея села до 15%, сеть пропала, наушники воткнули. BroadcastReceiver — это почтовый ящик, куда эти письма приходят. Вам остаётся только открыть его и прочитать.
Приёмник может быть зарегистрирован двумя способами: статически (в манифесте) или динамически (в коде). Статический работает даже когда приложение не запущено, но в современных версиях Android для большинства событий этот способ ограничен. Динамический регистрируется, когда приложение активно, и отключается вместе с ним — он безопаснее и проще для начала.
Создаём приёмник заряда батареи
Начнём с практического примера: будем показывать процент зарядки прямо в приложении. Создайте класс, наследующий BroadcastReceiver, и переопределите метод onReceive. Внутри этого метода из Intent можно извлечь текущий уровень батареи.
class BatteryReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale = intent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
val percent = (level * 100 / scale)
// здесь можно обновить UI или показать уведомление
}
}
Два значения — EXTRA_LEVEL (текущий уровень) и EXTRA_SCALE (максимальный уровень) — нужны, чтобы вычислить процент. У разных устройств scale может отличаться, поэтому просто взять level недостаточно.
Регистрируем и отменяем приёмник в Activity
Динамическая регистрация делается через метод registerReceiver. Лучшее место для этого — onResume. А в onPause нужно обязательно отменить регистрацию, иначе приложение будет получать события даже когда неактивно, расходуя батарею.
class MainActivity : AppCompatActivity() {
private val batteryReceiver = BatteryReceiver()
override fun onResume() {
super.onResume()
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
registerReceiver(batteryReceiver, filter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(batteryReceiver)
}
}
IntentFilter указывает, какие именно события нас интересуют. Действие ACTION_BATTERY_CHANGED посылается системой при любом изменении состояния батареи — зарядке, разрядке, подключении к питанию.
Показываем результат на экране
Сам по себе BroadcastReceiver не имеет доступа к UI, потому что это отдельный компонент. Чтобы обновить текст на экране, можно передать лямбду в конструктор приёмника и вызвать её при получении данных.
class BatteryReceiver(
private val onUpdate: (Int) -> Unit
) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale = intent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
val percent = (level * 100 / scale)
onUpdate(percent)
}
}
// в Activity
private val batteryReceiver = BatteryReceiver { percent ->
batteryText.text = "Заряд: $percent%"
}
Слушаем подключение наушников
По такому же принципу можно отследить, когда пользователь воткнул или вытащил наушники. Действие называется ACTION_HEADSET_PLUG. Intent будет содержать состояние — 1 (подключены) или 0 (отключены).
class HeadsetReceiver(
private val onStateChanged: (Boolean) -> Unit
) : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val state = intent?.getIntExtra("state", 0) ?: 0
onStateChanged(state == 1)
}
}
// в Activity
private val headsetReceiver = HeadsetReceiver { connected ->
val message = if (connected) "Наушники подключены" else "Наушники отключены"
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
override fun onResume() {
super.onResume()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
registerReceiver(headsetReceiver, IntentFilter(Intent.ACTION_HEADSET_PLUG))
}
Несколько замечаний для начинающих
- Всегда отменяйте регистрацию. Если забыть
unregisterReceiver, система выдаст ошибку, а батарея будет садиться быстрее. - Не делайте долгих операций в onReceive. Этот метод выполняется в главном потоке и должен отработать быстро. Для длительных задач запускайте Service или WorkManager.
- Проверяйте наличие действия. Один приёмник можно подписать на несколько событий, но внутри onReceive нужно различать их через
intent?.action.
Что мы сегодня освоили
Сегодняшний урок в Android Studio на языке Kotlin показал, как приложение может откликаться на системные события с помощью BroadcastReceiver. Вы научились создавать приёмник, регистрировать его динамически и получать данные о батарее и наушниках. Эти знания помогут делать приложения более отзывчивыми и дружелюбными. Попробуйте добавить отслеживание состояния сети — это будет отличным продолжением сегодняшней темы.