← Назад к вопросам

Какие знаешь ограничения на выполнение операций внутри Broadcast Receiver?

1.8 Middle🔥 111 комментариев
#Android компоненты

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ограничения на выполнение операций в Broadcast Receiver

Broadcast Receiver — компонент со строгими ограничениями. Понимание этих ограничений критично для стабильного приложения.

1. Timeout (10 секунд)

onReceive() должен завершиться за 10 секунд, иначе ANR:

// ❌ НЕПРАВИЛЬНО — 15 секунд работы
class LongOperationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Долгая операция
        Thread.sleep(15000)  // ANR!
    }
}

// ✅ ПРАВИЛЬНО — Запустить работу в Service или WorkManager
class QuickReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Быстро запустить работу и выйти
        val serviceIntent = Intent(context, MyService::class.java)
        context.startService(serviceIntent)
        
        // Или лучше WorkManager
        WorkManager.getInstance(context).enqueueUniqueWork(
            "work",
            ExistingWorkPolicy.KEEP,
            OneTimeWorkRequestBuilder<MyWorker>().build()
        )
    }
}

2. Запрещено создавать Threads

Он может быть убит до завершения потока:

// ❌ НЕПРАВИЛЬНО
class BadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Thread {
            // Может не выполниться!
            saveToDatabase()
        }.start()
    }
}

// ✅ ПРАВИЛЬНО
class GoodReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Синхронно и быстро
        val sharedPref = context.getSharedPreferences("app", Context.MODE_PRIVATE)
        sharedPref.edit().putString("event", "received").apply()
    }
}

3. Запрещено запускать Activities

Это плохой UX — пользователь не ожидает:

// ❌ НЕПРАВИЛЬНО
class BadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intent = Intent(context, MyActivity::class.java)
        context.startActivity(intent)  // Не делай так!
    }
}

// ✅ ПРАВИЛЬНО — Показать Notification если нужно
class GoodReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Создать notification
        val notification = NotificationCompat.Builder(context, "channel")
            .setContentTitle("Event")
            .setSmallIcon(R.drawable.ic_icon)
            .setContentIntent(PendingIntent.getActivity(
                context,
                0,
                Intent(context, MyActivity::class.java),
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            ))
            .build()
        
        val notificationManager = NotificationManagerCompat.from(context)
        notificationManager.notify(1, notification)
    }
}

4. Запрещены async операции (без обработки исключений)

Частичные операции оставляют приложение в невалидном состоянии:

// ❌ НЕПРАВИЛЬНО — может не завершиться
class BadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val job = GlobalScope.launch {
            delay(5000)
            updateData()
        }
        // onReceive выходит, процесс может быть убит!
    }
}

// ✅ ПРАВИЛЬНО
class GoodReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Либо синхронно
        updateDataSync()
        
        // Либо через Service/WorkManager если async нужна
        val work = OneTimeWorkRequestBuilder<UpdateWorker>().build()
        WorkManager.getInstance(context).enqueueUniqueWork(
            "update",
            ExistingWorkPolicy.KEEP,
            work
        )
    }
}

5. Ограничено использование получения результата (ordered broadcasts)

Для ordered broadcasts можешь использовать результаты, но с осторожностью:

// Ordered broadcast — приёмники получают по очереди
class PriorityReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val data = intent.getStringExtra("data")
        
        // Установить результат для следующего приёмника
        resultData = "processed_$data"
        
        // Отменить broadcast для приёмников с меньшим приоритетом
        abortBroadcast()
    }
}

// AndroidManifest.xml
<receiver android:name=".PriorityReceiver">
    <intent-filter android:priority="100">
        <action android:name="com.example.ACTION" />
    </intent-filter>
</receiver>

6. Память и Context утечки

Context может быть освобожден очень быстро:

// ❌ НЕПРАВИЛЬНО
class BadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Не сохраняй context на уровне класса!
        MyGlobalState.context = context  // УТЕЧКА
    }
}

// ✅ ПРАВИЛЬНО
class GoodReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Используй context только внутри метода
        val prefs = context.getSharedPreferences("app", Context.MODE_PRIVATE)
        prefs.edit().putBoolean("received", true).apply()
    }
}

7. Broadcast Receiver умирает с процессом приложения

Eсли приложение убито, broadcast также будет проигнорирован (зависит от версии Android):

// Android 8+ — запрещены implicit broadcasts для фоновых приложений
// Используй explicit intent к конкретному приемнику

// ❌ НЕПРАВИЛЬНО — может не сработать на Android 8+
val intent = Intent("com.example.ACTION")
context.sendBroadcast(intent)

// ✅ ПРАВИЛЬНО
val intent = Intent("com.example.ACTION")
intent.setPackage("com.example.app")
context.sendBroadcast(intent)

8. Запрещены сетевые операции без async

HTTP запрос займет больше 10 секунд:

// ❌ НЕПРАВИЛЬНО
class BadReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val response = Retrofit.create(Api::class.java)
            .getUser("123")
            .execute()  // Блокирует на 5+ секунд
    }
}

// ✅ ПРАВИЛЬНО — через WorkManager
class GoodReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val work = OneTimeWorkRequestBuilder<NetworkWorker>().build()
        WorkManager.getInstance(context).enqueue(work)
    }
}

class NetworkWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        return try {
            val response = Retrofit.create(Api::class.java)
                .getUser("123")
                .execute()
            // Сохранить результат
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

9. Ограничение на Manifest-declared receivers (Android 8+)

Многие implicit broadcasts просто не доходят до приложения:

// Список действий которые ВСЕ ЕЩЕ работают в фоне:
// ACTION_BOOT_COMPLETED
// ACTION_LOCKED_BOOT_COMPLETED
// ACTION_SHUTDOWN
// ACTION_BATTERY_LOW
// ACTION_BATTERY_OKAY
// ACTION_DEVICE_STORAGE_LOW
// ACTION_DEVICE_STORAGE_OK
// Остальные требуют явного запуска или динамической регистрации

10. Использование goAsync() для долгих операций

Для операций которые немного дольше 10 секунд:

class LongerReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val pendingResult = goAsync()
        
        // На фоновом потоке (в пуле)
        Thread {
            try {
                // До 30 секунд на некоторых системах
                val result = doSlightlyLongerWork()
                pendingResult.setResultCode(Activity.RESULT_OK)
            } finally {
                pendingResult.finish()
            }
        }.start()
    }
}

Best Practices

  • Receiver должна быть очень быстрой (< 1 секунда)
  • Используй WorkManager для долгих операций
  • Не запускай Activities из Receiver
  • Не создавай Threads в Receiver
  • Не сохраняй Context на уровне класса
  • Используй SharedPreferences для быстрого хранения
  • Явный intent для broadcast на Android 8+
  • Регистрируй динамически если нужны неявные actions
Какие знаешь ограничения на выполнение операций внутри Broadcast Receiver? | PrepBro