← Назад к вопросам
Какие знаешь ограничения на выполнение операций внутри 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