- Home »

Учебник по Android BroadcastReceiver с примером
Серверному админу мобильная разработка может показаться чужеродной территорией, но современные DevOps-практики всё чаще требуют понимания того, как работают клиентские приложения. Особенно когда речь идёт о push-уведомлениях, интеграции с сервисами и мониторинге. BroadcastReceiver — это системный механизм Android, который позволяет приложениям реагировать на события как внутри системы, так и между приложениями. Понимание этого компонента поможет вам лучше проектировать API, настраивать уведомления и даже создавать собственные решения для мониторинга мобильного трафика.
Что такое BroadcastReceiver и зачем он нужен?
BroadcastReceiver — это один из четырёх основных компонентов Android (вместе с Activity, Service и ContentProvider), который работает по принципу publish-subscribe. Думайте о нём как о системном EventBus, который позволяет приложениям подписываться на различные события и реагировать на них.
Основные типы событий:
- Системные broadcasts — изменение состояния батареи, подключение к WiFi, входящие SMS
- Пользовательские broadcasts — события, которые отправляет ваше приложение
- Локальные broadcasts — события внутри одного приложения
С точки зрения серверного админа, это аналог демонов в Linux, которые слушают определённые сигналы и выполняют действия.
Как это работает под капотом?
Android использует Binder IPC (Inter-Process Communication) для доставки broadcasts. Когда система или приложение отправляет broadcast, Android Manager Service обрабатывает его и доставляет всем зарегистрированным получателям.
Процесс выглядит так:
- Отправитель создаёт Intent с определённым action
- Система находит всех зарегистрированных получателей
- Запускается метод onReceive() у каждого получателя
- Получатель обрабатывает событие (максимум 10 секунд)
Пошаговая настройка BroadcastReceiver
Шаг 1: Создание BroadcastReceiver
Создаём класс, наследующий от BroadcastReceiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
Log.d("NetworkReceiver", "Network connected: " + networkInfo.getTypeName());
// Отправляем данные на сервер
sendDataToServer(context);
} else {
Log.d("NetworkReceiver", "Network disconnected");
// Сохраняем данные локально
saveDataLocally(context);
}
}
}
private void sendDataToServer(Context context) {
// Здесь ваша логика отправки данных
// Например, синхронизация с вашим API
}
private void saveDataLocally(Context context) {
// Сохранение данных в локальную БД
}
}
Шаг 2: Регистрация в AndroidManifest.xml
<receiver android:name=".NetworkChangeReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Шаг 3: Динамическая регистрация (альтернатива)
public class MainActivity extends AppCompatActivity {
private NetworkChangeReceiver networkReceiver;
@Override
protected void onResume() {
super.onResume();
networkReceiver = new NetworkChangeReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkReceiver, filter);
}
@Override
protected void onPause() {
super.onPause();
if (networkReceiver != null) {
unregisterReceiver(networkReceiver);
}
}
}
Практические примеры и кейсы
Кейс 1: Мониторинг состояния сервера
Создаём receiver для проверки доступности сервера при подключении к сети:
public class ServerMonitorReceiver extends BroadcastReceiver {
private static final String SERVER_URL = "https://your-server.com/api/health";
@Override
public void onReceive(Context context, Intent intent) {
if (isNetworkAvailable(context)) {
new Thread(() -> {
try {
HttpURLConnection connection = (HttpURLConnection)
new URL(SERVER_URL).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
Log.i("ServerMonitor", "Server is healthy");
notifyServerStatus(context, true);
} else {
Log.w("ServerMonitor", "Server returned: " + responseCode);
notifyServerStatus(context, false);
}
} catch (IOException e) {
Log.e("ServerMonitor", "Server check failed", e);
notifyServerStatus(context, false);
}
}).start();
}
}
private boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
private void notifyServerStatus(Context context, boolean isHealthy) {
Intent intent = new Intent("com.yourapp.SERVER_STATUS");
intent.putExtra("is_healthy", isHealthy);
context.sendBroadcast(intent);
}
}
Кейс 2: Автоматическая синхронизация логов
Receiver для отправки логов на сервер при подключении к WiFi:
public class LogSyncReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (isWifiConnected(context)) {
startLogSyncService(context);
}
}
private boolean isWifiConnected(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
return networkInfo != null &&
networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
}
private void startLogSyncService(Context context) {
Intent serviceIntent = new Intent(context, LogSyncService.class);
context.startService(serviceIntent);
}
}
Сравнение способов регистрации
Способ | Преимущества | Недостатки | Использование |
---|---|---|---|
Manifest Registration | • Работает даже когда приложение закрыто • Автоматическая регистрация |
• Потребляет больше ресурсов • Ограничения в Android 8.0+ |
Системные события, критические уведомления |
Dynamic Registration | • Лучшая производительность • Полный контроль жизненного цикла |
• Работает только когда приложение активно • Требует ручного управления |
События во время работы приложения |
LocalBroadcastManager | • Максимальная безопасность • Высокая производительность |
• Только внутри приложения • Deprecated в Android 9.0+ |
Внутренние события приложения |
Ограничения и подводные камни
Android 8.0+ Background Execution Limits
Начиная с Android 8.0, Google значительно ограничил возможности background receivers. Многие системные broadcasts больше не работают в manifest-зарегистрированных receivers.
Список ограниченных broadcasts:
CONNECTIVITY_ACTION
ACTION_NEW_PICTURE
ACTION_NEW_VIDEO
BATTERY_OKAY
Решение — использовать JobScheduler или WorkManager:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class NetworkJobService extends JobService {
private static final int JOB_ID = 1000;
public static void scheduleJob(Context context) {
JobScheduler jobScheduler = (JobScheduler)
context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
new ComponentName(context, NetworkJobService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build();
jobScheduler.schedule(jobInfo);
}
@Override
public boolean onStartJob(JobParameters params) {
// Выполняем работу в фоновом потоке
new Thread(() -> {
// Ваша логика здесь
jobFinished(params, false);
}).start();
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
Интеграция с серверными решениями
Push-уведомления через Firebase
Receiver для обработки FCM-сообщений:
public class FCMReceiver extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String serverCommand = remoteMessage.getData().get("command");
switch (serverCommand) {
case "sync_data":
syncDataWithServer();
break;
case "update_config":
updateAppConfig(remoteMessage.getData());
break;
case "maintenance_mode":
enableMaintenanceMode();
break;
}
}
private void syncDataWithServer() {
// Синхронизация с вашим API
}
private void updateAppConfig(Map<String, String> data) {
// Обновление конфигурации приложения
}
private void enableMaintenanceMode() {
// Включение режима обслуживания
}
}
Webhook-подобная функциональность
Создаём receiver, который отправляет данные на сервер при определённых событиях:
public class WebhookReceiver extends BroadcastReceiver {
private static final String WEBHOOK_URL = "https://your-server.com/webhook";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
JSONObject payload = new JSONObject();
try {
payload.put("timestamp", System.currentTimeMillis());
payload.put("device_id", getDeviceId(context));
payload.put("event", action);
if (Intent.ACTION_BATTERY_LOW.equals(action)) {
payload.put("battery_level", getBatteryLevel(context));
}
sendWebhook(payload);
} catch (JSONException e) {
Log.e("WebhookReceiver", "JSON error", e);
}
}
private void sendWebhook(JSONObject payload) {
// Отправка данных на сервер
new Thread(() -> {
try {
HttpURLConnection connection = (HttpURLConnection)
new URL(WEBHOOK_URL).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
Log.d("WebhookReceiver", "Webhook sent, response: " + responseCode);
} catch (IOException e) {
Log.e("WebhookReceiver", "Webhook failed", e);
}
}).start();
}
}
Альтернативные решения
EventBus
Для внутренних событий приложения часто используется EventBus:
// Подписка на события
@Subscribe(threadMode = ThreadMode.MAIN)
public void onNetworkEvent(NetworkEvent event) {
if (event.isConnected) {
syncWithServer();
}
}
// Отправка события
EventBus.getDefault().post(new NetworkEvent(true));
RxJava для реактивного программирования
Использование RxJava для обработки системных событий:
public class RxNetworkMonitor {
public static Observable<Boolean> networkChanges(Context context) {
return Observable.create(emitter -> {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean isConnected = isNetworkAvailable(context);
emitter.onNext(isConnected);
}
};
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(receiver, filter);
emitter.setCancellable(() -> context.unregisterReceiver(receiver));
});
}
}
Мониторинг и отладка
Для отладки BroadcastReceiver можно использовать ADB команды:
# Отправка тестового broadcast
adb shell am broadcast -a android.intent.action.BATTERY_LOW
# Мониторинг всех broadcasts
adb shell dumpsys activity broadcasts
# Просмотр зарегистрированных receivers
adb shell dumpsys package | grep -A 10 "Registered Receivers"
Автоматизация и скрипты
BroadcastReceiver открывает возможности для автоматизации:
- Автоматическое развёртывание — receiver может получать команды с сервера для обновления конфигурации
- Мониторинг устройств — отправка статистики на сервер мониторинга
- Удалённое управление — выполнение команд через push-уведомления
- Синхронизация данных — автоматическая загрузка/выгрузка данных при изменении состояния сети
Если вы планируете разрабатывать серверную часть для мобильных приложений, рекомендую использовать VPS-сервер с предустановленным стеком для API. Для высоконагруженных решений лучше подойдёт выделенный сервер.
Выводы и рекомендации
BroadcastReceiver — мощный инструмент для создания реактивных мобильных приложений. Основные рекомендации:
- Используйте динамическую регистрацию для событий, которые нужны только во время работы приложения
- Переходите на JobScheduler/WorkManager для фоновых задач в Android 8.0+
- Ограничивайте время выполнения в onReceive() — максимум 10 секунд
- Используйте IntentService или WorkManager для длительных операций
- Применяйте LocalBroadcastManager для внутренних событий (если target SDK < 28)
Для серверных админов понимание BroadcastReceiver поможет лучше проектировать API для мобильных приложений, настраивать push-уведомления и создавать эффективные системы мониторинга мобильного трафика.
Помните: с большой силой приходит большая ответственность. Неправильно настроенные receivers могут серьёзно повлиять на производительность устройства и время работы от батареи.
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.