Context, Intent и четыре компонента приложения
Три вопроса, за которыми стоит одна тема: как ваш код разговаривает с системой и с другими приложениями.
Context — точка доступа к среде приложения: ресурсам, системным сервисам, файлам, запуску компонентов. Не «god object», а интерфейс к Android для конкретного участка кода.
Вопрос 1: «Что такое Context и какие виды бывают?»
Что проверяет интервьюер
Понимаете ли вы, что разные Context имеют разное время жизни. Из этого напрямую растёт самая частая утечка памяти в Android-приложениях.
Развёрнутый ответ
Практически различают два вида:
- Application context — живёт столько же, сколько процесс. Получается через
context.applicationContext. Годится для того, что переживает экраны: синглтоны, база данных, DI-граф,WorkManager. - Activity context — живёт ровно столько, сколько экран. Знает про тему оформления и про окно. Нужен для инфляции разметки, диалогов, запуска новых экранов из UI.
Кроме них есть Service context, context у BroadcastReceiver (ограниченный: из него нельзя показывать UI и регистрировать приёмники) и ContextThemeWrapper, который оборачивает другой context, подменяя тему.
// УТЕЧКА: синглтон переживёт Activity и удержит её вместе со всеми View
object Analytics {
lateinit var context: Context // сюда положили Activity — утечка на весь процесс
fun init(context: Context) {
this.context = context
}
}
// Правильно: явно требуем Application context
class Analytics(private val app: Application) { /* ... */ }
// или так, если конструктор принимает произвольный Context
class Analytics(context: Context) {
private val appContext = context.applicationContext
}
Обратное правило тоже важно: Application context нельзя использовать где попало. Диалог требует Activity — ему нужен window token и тема. Попытка показать AlertDialog с application context даёт BadTokenException. Инфляция разметки с application context «работает», но берёт системную тему вместо вашей — и вёрстка выглядит поплывшей.
Ещё частый вопрос: почему startActivity с application context падает? Потому что у него нет задачи (task), в которую поместить новый экран — нужен флаг FLAG_ACTIVITY_NEW_TASK, и это, как правило, признак того, что архитектура пошла не туда.
Вопрос 2: «Explicit и implicit Intent — в чём разница?»
Что проверяет интервьюер
Знаете ли вы, что Intent — это не «способ открыть экран», а сообщение системе, которое она маршрутизирует.
Развёрнутый ответ
Explicit intent называет получателя по имени класса. Так вы открываете свои экраны и запускаете свои сервисы. Implicit intent описывает намерение — action, category, data — а получателя ищет система среди приложений с подходящим intent-filter.
// explicit — знаем класс получателя
startActivity(Intent(this, DetailsActivity::class.java).apply {
putExtra("itemId", 42L)
})
// implicit — описываем намерение, получателя выберет система
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://codechick.io"))
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
<activity android:name=".DeepLinkActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="codechick.io" />
</intent-filter>
</activity>
Что добавит вам очков на middle-собеседовании:
- Начиная с Android 12 любой компонент с
intent-filterобязан явно объявлятьandroid:exported, иначе приложение не установится. - Начиная с Android 11
resolveActivityиqueryIntentActivitiesвидят не все приложения — работает package visibility. Нужный пакет надо объявить в секции<queries>манифеста, иначе система «не найдёт» получателя. - PendingIntent — это не Intent, а токен, отдающий чужому процессу право выполнить действие от вашего имени (уведомления, виджеты, алармы). Начиная с Android 12 обязателен флаг
FLAG_IMMUTABLEилиFLAG_MUTABLE; по умолчанию берите immutable — это вопрос безопасности.
Вопрос 3: «Назовите компоненты приложения»
| Компонент | Зачем | Что спросят дополнительно |
Activity | экран с UI | жизненный цикл, task и back stack, launch modes |
Service | работа без UI | чем foreground service отличается от обычного, почему фоновая работа сегодня — это WorkManager |
BroadcastReceiver | реакция на системные события | манифест против регистрации в коде, лимиты неявных broadcast с Android 8, флаг exported с Android 13 |
ContentProvider | отдача данных другим приложениям | зачем нужен, если внутри приложения хватает Room |
Все четыре объявляются в AndroidManifest.xml (кроме приёмников, зарегистрированных в коде). Важный современный акцент: Service для отложенной фоновой работы почти всегда неверный выбор — система его убьёт. Правильный ответ — WorkManager, а foreground service — только для того, что пользователь видит прямо сейчас (навигация, плеер, запись трека).
Типичные ошибки кандидатов
- «Context нужен, чтобы получить ресурсы» — верно, но не отвечает на вопрос о видах и времени жизни.
- Хранят Activity в статических полях или синглтонах — самая частая утечка.
- Путают
Serviceи поток: сервис по умолчанию работает на главном потоке и сам по себе ничего не распараллеливает. - Считают
PendingIntentобычным интентом с задержкой.
Как ответить кратко (20–30 секунд)
«Context — доступ к ресурсам, сервисам и запуску компонентов. Различаю два по времени жизни: application context живёт весь процесс и годится для синглтонов и БД, activity context живёт столько же, сколько экран, знает тему и окно, поэтому нужен для диалогов и инфляции. Держать activity context в синглтоне — классическая утечка. Intent бывает explicit — с конкретным классом получателя, и implicit — описывает action и data, а получателя система ищет по intent-filter; с Android 11 тут ещё работает package visibility. Компонентов четыре: Activity, Service, BroadcastReceiver, ContentProvider, все объявляются в манифесте, и для отложенной фоновой работы сегодня берут WorkManager, а не Service.»