Как мыслить о компонентах Android‑приложения

Короткий ответ: Android‑приложение — набор компонентов (Activity, Service, BroadcastReceiver, ContentProvider), которыми ОС управляет отдельно; ваша задача — распределить ответственность: UI в Activity, фоновые задачи в Service/WorkManager, реакции на события в BroadcastReceiver. Ниже — практические правила и конкретные сценарии.

Activity: экран, жизненный цикл и что туда не класть

Activity — это представление экрана и вход пользователя. Делайте в Activity только UI, навигацию и привязку к ViewModel.

Ключевые коллбеки и что в них выполнять:

  • onCreate(): inflate, DI, привязка ViewModel — не делайте тяжёлых операций.
  • onStart()/onStop(): привязывайте ресурсы уровня видимости (камера, сенсоры).
  • onResume()/onPause(): подписки на UI‑события, анимации.
  • onSaveInstanceState(): сохраняйте минимум состояния (UI‑поля); большие данные — в ViewModel/репозитории.

Практический лайфхак:

Переносите загрузки в ViewModel + Coroutines/LiveData; при пересоздании Activity данные сохранятся, а UI обновится автоматически.

Service: когда нужен и какие есть типы

Service — для работы, которая должна пережить Activity или выполняться в фоне.

Типы:

  • Started Service (startService/startForegroundService): подходит для явных фоновых задач; для длительных фоновых задач используйте foreground с уведомлением.
  • Bound Service (bindService): когда нужна двусторонняя связь между UI и долгоживущей логикой (например, медиаплеер).
  • WorkManager/JobScheduler: предпочтителен для отложенных/повторяемых фоновых задач — система лучше управляет энергопотреблением и ограничениями.

Жизненный цикл и важные флаги:

  • onStartCommand(Intent...): возвращайте START_NOT_STICKY / START_STICKY / START_REDELIVER_INTENT в зависимости от желаемого поведения при убийстве процесса.
  • onBind/onUnbind для привязки клиентов.

Предупреждение:

Не делайте «вечный» сервис без foreground‑уведомления и явной причины — современные Android ограничивают фоновые сервисы.

BroadcastReceiver: триггеры, регистрация и что туда не класть

BroadcastReceiver — быстрый обработчик Intent‑событий. onReceive() выполняется кратко; процесс может быть убит сразу после.

Правила:

  • Не выполняйте тяжёлую работу в onReceive(). Запускайте Service или планируйте WorkManager‑задачу.
  • Динамическая регистрация (registerReceiver) — для слушания только при активном контексте (Activity/Service).
  • Статическая регистрация (в манифесте) — для событий, которые должны работать при перезагрузке устройства (BOOT_COMPLETED), но многие события ограничены на новых версиях Android.

Используйте BroadcastReceiver как триггер: проверили условия — делегировали задачу в WorkManager/Service.

Как компоненты работают вместе: три типичных сценария

  1. Загрузка файла с прогрессом: Activity → startForegroundService() (загрузка) → Service пишет в БД → локальный broadcast/LiveData информирует Activity об окончании.
  2. Сеть: динамический Receiver при открытом экране — обнаружил сеть → запустил WorkManager для синхронизации.
  3. Перезагрузка устройства: статический Receiver BOOT_COMPLETED → планирует напоминания через WorkManager.

Частые ошибки

  • Перегруженный onCreate() (сеть/парсинг) — переносите в ViewModel/воркеры.
  • Долгие операции в onReceive() — используйте Service/WorkManager.
  • Хранение ссылки на Activity в синглтоне — ведёт к утечкам; используйте Application‑контекст для долгоживущих объектов.
  • Использование Service вместо WorkManager для фоновых задач, которые можно отложить.

FAQ

  • Нужно ли всегда использовать Foreground Service для фоновой работы?
    Только если задача реально должна быть видима пользователю (навигация, музыка). Для отложенных или невременных задач — WorkManager.

  • Как пережить поворот экрана без потери данных?
    Храните состояние во ViewModel и в onSaveInstanceState сохраняйте минимальные UI‑поля.

  • Когда регистрировать BroadcastReceiver динамически?
    Когда слушать нужно только при видимом UI или ограниченном по времени контексте (например, при загрузке данных).

Итог: думайте о компонентах как адаптерах к платформе — держите бизнес‑логику в нормальных классах и используйте Activity/Service/Receiver только для интерфейса с ОС. Это сделает приложение предсказуемым и устойчивым.