Чем отличаются Context, Application и Service и когда что использовать
Короткий ответ: для UI и всего, что связано с окном/темой, используйте context Activity/Fragment; для долгоживущих singletons и системных API — applicationContext; для задач, которые должны работать после закрытия экрана, — Service (обычно foreground), но сначала рассмотрите WorkManager.
Context — что это и как выбирать
Context — интерфейс доступа к ресурсам и системным сервисам: ресурсы, файлы, getSystemService(), запуск компонентов. В Android его реализуют Activity, Service и Application, а также обёртки (ContextWrapper).
Практические правила:
- UI (диалоги, темы, навигация) — Activity/Fragment context:
this,requireContext(),requireActivity(). - Долговечные объекты (репозитории, кеши, DB) —
applicationContext. - Вью берет свой
context, но не храните Activity в статических полях.
Неправильный выбор Context — частая причина утечек памяти и исключений WindowManager$BadTokenException.
Application — глобальная инициализация
Application создаётся один раз на запуск процесса и живёт до завершения. Это Context без UI, удобный для инициализации и хранения компонентов, которые должны жить на весь процесс.
Когда использовать:
- Инициализация DI, логирования, баз данных.
- Передача
applicationContextв singletons. - Хранение кешей и глобальных менеджеров.
Пример (Kotlin):
class App : Application() {
override fun onCreate() {
super.onCreate()
initDI()
initLogger()
}
}
Когда не использовать:
- Для построения диалогов, PopupMenu, тем — нужен Activity context.
- Не используйте
applicationContextдля операций, завязанных на окно/тему.
Не прокидывайте applicationContext в адаптеры для построения диалогов или в навигацию — это приведёт к ошибкам и плохому UX.
Service — для настоящих фоновых задач (и альтернативы)
Service — компонент без UI, реализует Context, но выполняется в UI-потоке по умолчанию. Используйте Service, когда задача должна продолжаться после закрытия Activity (музыка, геотрекинг). Для коротких или отложенных задач чаще подойдёт WorkManager или корутина в ViewModel.
Ключевые моменты:
- Service не создаёт новый поток — вы сами переносите работу в корутину/поток.
- Для долгих задач, требующих видимости пользователю, используйте foreground service с уведомлением.
- Для отложенной/периодической работы предпочитайте WorkManager (с учётом ограничений Doze).
Пример стартового Service:
class MyService : Service() {
override fun onBind(intent: Intent?) = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
CoroutineScope(Dispatchers.Default).launch { doWork() }
return START_STICKY
}
}
Частые ошибки
- Хранение Activity/Fragment в singletons -> утечки памяти.
- Использование
applicationContextдля UI-операций -> BadTokenException/неправильная тема. - Запуск Service для коротких фоновых операций вместо WorkManager -> лишний расход батареи.
- Предположение, что Service выполняется в отдельном потоке.
FAQ
- Нужно ли всегда использовать WorkManager вместо Service?
- Нет. Для длительных задач, связанных с видимой нотификацией/аудио/трекингом лучше Service (foreground). Для отложенной/периодической работы — WorkManager.
- Можно ли хранить DB-инстанс в Application?
- Да. Инициализируйте в Application и используйте
applicationContextпри создании.
- Да. Инициализируйте в Application и используйте
- Как избежать утечки при передаче Context в библиотеки?
- Передавайте
applicationContextдля долгоживущих объектов; для UI передавайте Activity/Fragment и не сохраняйте их в static.
- Передавайте
Хорошее практическое правило: всё, что может пережить экран — привязывайте к applicationContext; всё, что связано с окном, темой и жизненным циклом — к Activity/Fragment; если задача должна выполняться без UI — подумайте Service, но сначала проверьте WorkManager.