BroadcastReceiver

https://developer.android.com/develop/background-work/background-tasks/broadcasts
https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions
BroadcastReceiver

Компонент, который позволяет приложению слушать и реагировать на системные или пользовательские широковещательные сообщения (broadcasts).

class MyBroadcastReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {}
}
sendBroadcast

Отправляет обычное широковещательное сообщение всем зарегистрированным получателям одновременно. Все получатели получат сообщение одновременно, и порядок получения не гарантируется.

val intent = Intent("your.custom.action")
sendBroadcast(intent)
sendOrderedBroadcast

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

val intent = Intent("your.custom.action")
sendOrderedBroadcast(intent, null)
onReceive

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

override fun onReceive(context: Context, intent: Intent) {
    // Обработка полученного сообщения
    val message = intent.getStringExtra("message")
    Toast.makeText(context, "Received: $message", Toast.LENGTH_SHORT).show()
}
registerReceiver

Используется для регистрации экземпляра BroadcastReceiver с IntentFilter, чтобы получать определенные широковещательные сообщения. Метод должен вызываться из контекста, такого как Activity, Service или Application.

val receiver = MyBroadcastReceiver()
val filter = IntentFilter("ACTION_NAME")
registerReceiver(receiver, filter)
unregisterReceiver

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

unregisterReceiver(receiver)
LocalBroadcastManager
LocalBroadcastManager официально устарел и больше не поддерживается Google. Мигрируй на Flow.

Позволяет отправлять и получать широковещательные сообщения (broadcasts) внутри одного приложения. Он обеспечивает изолированное пространство для обмена данными между компонентами приложения без риска, что другие приложения смогут перехватить эти сообщения.

sendBroadcast

Отправка сообщения.

val intent = Intent("custom-event-name")
intent.putExtra("data", "Your data")
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
registerReceiver

Регистрация получателя.

val receiver = object: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // Получение данных из intent
        val data = intent?.getStringExtra("data")
        // Обработка данных
    }
}

val filter = IntentFilter("custom-event-name")
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter)
unregisterReceiver

Отмена регистрации получателя.

LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver)
Явный BroadcastReceiver (Explicit BroadcastReceiver)

Явный BroadcastReceiver регистрируется с указанием конкретного компонента (например, класса), который будет обрабатывать полученное сообщение. Это означает, что вы точно знаете, какой компонент будет обрабатывать ваш Broadcast.

val intent = Intent(this, MyBroadcastReceiver::class.java)
sendBroadcast(intent)
Неявный BroadcastReceiver (Implicit BroadcastReceiver)

Неявный BroadcastReceiver не указывает конкретный компонент, а использует фильтры намерений (intent filters) для определения, какие компоненты могут обработать полученное сообщение. В этом случае система определяет, какой компонент будет получать сообщение, основываясь на фильтре намерений.

val intent = Intent("your.custom.action")
sendBroadcast(intent)
Системные события
CONNECTIVITY_ACTION

Уведомляет о изменениях в состоянии подключения к сети (например, Wi-Fi, мобильные данные).

<receiver android:name=".ConnectivityReceiver">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
</receiver>
class ConnectivityReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == ConnectivityManager.CONNECTIVITY_ACTION) {
            val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetwork = connectivityManager.activeNetworkInfo
            if (activeNetwork != null && activeNetwork.isConnected) {
                Log.d("ConnectivityReceiver", "Device is connected to the internet")
            } else {
                Log.d("ConnectivityReceiver", "Device is not connected to the internet")
            }
        }
    }
}
WIFI_STATE_CHANGED

Сообщает о изменении состояния Wi-Fi (включено/выключено).

<receiver android:name=".WifiStateReceiver">
    <intent-filter>
        <action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
    </intent-filter>
</receiver>
class WifiStateReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val wifiState = intent?.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
        when (wifiState) {
            WifiManager.WIFI_STATE_ENABLED -> Log.d("WifiStateReceiver", "Wi-Fi is enabled")
            WifiManager.WIFI_STATE_DISABLED -> Log.d("WifiStateReceiver", "Wi-Fi is disabled")
        }
    }
}
BATTERY_CHANGED

Предоставляет информацию о состоянии батареи, например, уровень заряда, состояние (заряжается/разряжается) и тип батареи.

<receiver android:name=".BatteryReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BATTERY_CHANGED"/>
    </intent-filter>
</receiver>
class BatteryReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
        Log.d("BatteryReceiver", "Battery level: $level%")
    }
}
POWER_CONNECTED POWER_DISCONNECTED

Уведомляет, когда устройство подключено или отключено от зарядного устройства.

<receiver android:name=".PowerConnectedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
    </intent-filter>
</receiver>

<receiver android:name=".PowerDisconnectedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
    </intent-filter>
</receiver>
class PowerConnectedReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_POWER_CONNECTED) {
            Log.d("PowerConnectedReceiver", "Power connected")
        }
    }
}

class PowerDisconnectedReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_POWER_DISCONNECTED) {
            Log.d("PowerDisconnectedReceiver", "Power disconnected")
        }
    }
}
BOOT_COMPLETED

Срабатывает, когда устройство завершает загрузку. Позволяет запускать фоновую работу после перезагрузки.

<receiver android:name=".BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>
class BootReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
            Log.d("BootReceiver", "Device boot completed")
            // Запуск фоновой работы
        }
    }
}
TIME_CHANGED

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

<receiver android:name=".TimeChangedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.TIME_CHANGED"/>
    </intent-filter>
</receiver>
class TimeChangedReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_TIME_CHANGED) {
            Log.d("TimeChangedReceiver", "Time has changed")
        }
    }
}
PACKAGE_ADDED PACKAGE_REMOVED PACKAGE_CHANGED

Уведомляет о том, что приложение было установлено, удалено или изменено.

<receiver android:name=".PackageReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_ADDED"/>
        <data android:scheme="package"/>
    </intent-filter>
</receiver>
class PackageReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_PACKAGE_ADDED) {
            val packageName = intent.data?.encodedSchemeSpecificPart
            Log.d("PackageReceiver", "Package added: $packageName")
        }
    }
}
ACTION_DEVICE_STORAGE_LOW

Уведомляет о том, что пространство на устройстве становится низким.

<receiver android:name=".StorageReceiver">
    <intent-filter>
        <action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
    </intent-filter>
</receiver>
class StorageReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_DEVICE_STORAGE_LOW) {
            Log.d("StorageReceiver", "Device storage is low")
        }
    }
}
ACTION_DEVICE_STORAGE_OK

Срабатывает, когда место на устройстве снова становится достаточным.

<receiver android:name=".StorageOkReceiver">
    <intent-filter>
        <action android:name="android.intent.action.DEVICE_STORAGE_OK"/>
    </intent-filter>
</receiver>
class StorageOkReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_DEVICE_STORAGE_OK) {
            Log.d("StorageOkReceiver", "Device storage is okay")
        }
    }
}
SYNC_STATE_CHANGED

Уведомляет о том, что состояние синхронизации изменилось.

<receiver android:name=".SyncReceiver">
    <intent-filter>
        <action android:name="android.content.SyncAdapter.ACTION_SYNC_STATE_CHANGED"/>
    </intent-filter>
</receiver>
class SyncReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Log.d("SyncReceiver", "Sync state changed")
    }
}
ALARM_CHANGED

Сообщает о изменениях в настройках будильника.

<receiver android:name=".AlarmChangedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.ALARM_CHANGED"/>
    </intent-filter>
</receiver>
class AlarmChangedReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == AlarmManager.ACTION_ALARM_CHANGED) {
            Log.d("AlarmChangedReceiver", "Alarm state has changed")
        }
    }
}
USER_PRESENT

Срабатывает, когда пользователь разблокирует устройство.

<receiver android:name=".UserPresentReceiver">
    <intent-filter>
        <action android:name="android.intent.action.USER_PRESENT"/>
    </intent-filter>
</receiver>
class UserPresentReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_USER_PRESENT) {
            Log.d("UserPresentReceiver", "User has unlocked the device")
        }
    }
}
Вопросы на собесе (5)
  1. Для чего используется BroadcastReceiver?

    BroadcastReceiver используется для обработки широковещательных сообщений (Intents), позволяя приложению реагировать на системные события, такие как изменения сети или получение SMS. Он помогает управлять фоновыми задачами и обновлять интерфейс.

  1. Какие есть способы регистрации BroadcastReceiver?

    Явная регистрация с помощью метода registerReceiver(), позволяет динамически регистрировать приемник в определённом контексте, например, внутри Activity или Service.

    Неявная регистрация путём добавления <receiver> элемента в файл манифеста, позволяет автоматически получать широковещательные сообщения даже если приложение не запущено.

  1. Различие между регистрацией BroadcastReceiver в манифесте и созданием в коде?

    BroadcastReceiver, указанный в манифесте, автоматически активируется системой для получения широковещательных сообщений даже при неактивном приложении, в то время как кодовый BroadcastReceiver регистрируется программно и работает только в активном контексте (например, в Activity), что делает его временным.

  1. Различие между явным и неявным BroadcastReceiver?

    Явный BroadcastReceiver обрабатывает Intents, направленные на конкретный компонент приложения, в то время как неявный BroadcastReceiver реагирует на Intents, отправленные из других приложений, используя фильтры для определения обрабатываемых сообщений. Явный используется для внутренней коммуникации, а неявный — для взаимодействия с внешними приложениями.

  1. Какие ограничения есть у BroadcastReceiver?

    Начиная с Android 7.0 (API 24) не работают ACTION_NEW_PICTURE и ACTION_NEW_VIDEO, и объявление получателя в манифесте для CONNECTIVITY_ACTION.

    Начиная с Android 8.0 (API 26) система ограничивает получателей, объявленных в манифесте для большинства трансляций не нацеленных конкретно на приложение, можно регистрировать вручную.

    Начиная с Android 9 (API 28) не работает получение данных о местонахождении пользователя или данные, позволяющие установить личность (NETWORK_STATE_CHANGED_ACTION).