Home » Учебник по Android BroadcastReceiver с примером
Учебник по Android BroadcastReceiver с примером

Учебник по 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 обрабатывает его и доставляет всем зарегистрированным получателям.

Процесс выглядит так:

  1. Отправитель создаёт Intent с определённым action
  2. Система находит всех зарегистрированных получателей
  3. Запускается метод onReceive() у каждого получателя
  4. Получатель обрабатывает событие (максимум 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 могут серьёзно повлиять на производительность устройства и время работы от батареи.


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked