Подготовка к собеседованию — Android-разработчик
Колода из 161+ карточек с вопросами для собеседования по направлению «Android-разработчик» — по темам и уровню сложности, с возвратом ровно перед тем, как вы забудете. Посмотрите несколько карточек ниже, затем войдите, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
Бесплатно · вход через GitHub · ваш прогресс остаётся с вами.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Kotlin и система типов
11 карточекКорутины и Flow
12 карточекКомпоненты и жизненный цикл
10 карточекUI: Views и Jetpack Compose
11 карточекАрхитектура Android-приложений
10 карточекСеть и хранение данных
10 карточекПроизводительность и внутреннее устройство
10 карточекТестирование и инструменты
9 карточекОсновы CS
43 карточкиПоведенческое интервью
35 карточекПримеры вопросов
Несколько карточек из колоды — откройте ответ, затем войдите, чтобы учить весь набор по расписанию.
Чем val отличается от var и делает ли val объект неизменяемым?
Чем val отличается от var и делает ли val объект неизменяемым?
Короткий ответ: var — перезаписываемая ссылка, val — read-only: присвоить повторно нельзя. Но val замораживает только ссылку, а не содержимое объекта: val list = mutableListOf<Int>() спокойно принимает list.add(1). Настоящая неизменяемость — это read-only тип плюс val.
Подробно:
val a = mutableListOf(1, 2)
a.add(3) // ✅ ссылка та же, содержимое меняется
// a = mutableListOf() // ❌ val нельзя переприсвоить
var n = 0
n = 1 // ✅ var переприсваивается
val now: Long get() = System.currentTimeMillis() // val с getter — не константа!
const val API = "v1" // const — время компиляции, только примитивы и String
- val ≠ immutable — гарантирует лишь стабильность ссылки; изменяемость зависит от типа (
ListvsMutableList). - val с кастомным getter — вычисляется при каждом обращении, значение может меняться от вызова к вызову.
- const val — подставляется компилятором в место использования; допустим только на top-level или в
object/companion, значение — примитив или String.
⚠️ Частая ошибка: считать val синонимом «immutable». val про ссылку, а не про глубину объекта.
Что такое корутина и чем suspend отличается от блокировки потока?
Что такое корутина и чем suspend отличается от блокировки потока?
Короткий ответ: Корутина — легковесная единица конкурентности поверх потоков. Приостановка (suspend) «паркует» корутину и освобождает поток под другую работу; блокировка держит поток занятым. Поэтому тысячи корутин спокойно живут на одном потоке.
Подробно:
// Блокировка: поток занят и бесполезен
fun blocking() {
Thread.sleep(1000) // поток спит — недоступен никому
}
// Приостановка: корутина паркуется, поток свободен
suspend fun suspending() {
delay(1000) // поток в это время выполняет другие корутины
}
fun main() = runBlocking {
repeat(100_000) { launch { delay(1000) } } // ок даже на одном потоке
// 100 000 потоков с Thread.sleep(1000) — OutOfMemoryError
}
- Приостановка ≠ блокировка —
delayвозвращает управление диспатчеру,Thread.sleepудерживает поток. - Лёгкость — корутина это объект в куче (continuation + стейт), а не стек ~1 МБ, как у потока.
- Кооперативность — корутина уступает поток только в точках приостановки (suspension points).
⚠️ Частая ошибка: «саспенд-функция выполняется в фоновом потоке». Нет: suspend сам по себе поток не переключает — где выполняться, решает диспатчер.
Назови полный жизненный цикл Activity — какие колбэки и зачем нужен каждый?
Назови полный жизненный цикл Activity — какие колбэки и зачем нужен каждый?
Короткий ответ: Три «поднимающих» колбэка — onCreate → onStart → onResume — выводят экран к пользователю; три «опускающих» — onPause → onStop → onDestroy — убирают. onRestart вызывается, когда остановленная Activity снова возвращается на экран.
Подробно:
onCreate() ← создан: setContentView, init, чтение savedInstanceState
│
onStart() ← стал видимым
│
onResume() ← на переднем плане, принимает ввод
│
[ RESUMED — работает ]
│
onPause() ← потерял фокус (частично перекрыт)
│
onStop() ← полностью не виден ──onRestart()→onStart() при возврате
│
onDestroy() ← уничтожен (finish или нехватка памяти)
- onCreate — единственный обязательный; здесь инфляция layout, инициализация, восстановление из
savedInstanceState. - onStart / onStop — граница видимости: регистрируем и снимаем то, что нужно только видимому экрану.
- onResume / onPause — граница фокуса и ввода; onPause обязан быть коротким — следующий экран не покажется, пока он не вернётся.
- onDestroy — финал; может не прийти при убийстве процесса, поэтому критичное сохраняем раньше.
⚠️ Частая ошибка: считать onDestroy гарантированным местом для сохранения. При process death его не будет — сохраняйте в onSaveInstanceState / onStop.
Что такое рекомпозиция и что её запускает?
Что такое рекомпозиция и что её запускает?
Короткий ответ: Рекомпозиция — повторный вызов @Composable-функций, когда меняется прочитанное ими состояние. Запускает её запись в наблюдаемый State (mutableStateOf, StateFlow через collectAsState и т.п.), который был прочитан внутри composable. Перевызываются только те функции, что читали именно это значение.
Подробно:
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Text("Clicks: $count") // читает count → перевызовется
Button(onClick = { count++ }) { // запись в count → рекомпозиция
Text("Tap") // count не читает → пропустится
}
}
- Триггер — не «любое изменение», а запись в snapshot-состояние, которое читалось в конкретной composable. Compose отслеживает чтения и инвалидирует ровно нужные scope'ы.
- Оптимистична — если во время рекомпозиции состояние снова поменялось, текущий проход отбрасывается и стартует заново.
- Неупорядочена и может идти параллельно — порядок выполнения соседних composable не гарантирован; нельзя закладываться на side-effect'ы прямо в теле.
⚠️ Частая ошибка: обычная var без mutableStateOf — это не state; её изменение Compose не видит и рекомпозицию не запустит, UI «застынет».
Что такое MVVM и почему ViewModel не должна ссылаться на View или Context?
Что такое MVVM и почему ViewModel не должна ссылаться на View или Context?
Короткий ответ: MVVM делит экран на три роли: Model (данные и логика), View (Activity/Fragment/Composable — только рисует и передаёт действия) и ViewModel (держит состояние и переживает пересоздание View). ViewModel не знает про конкретную View — она лишь публикует состояние, на которое View подписывается.
Подробно:
┌────────┐ подписка на state ┌───────────┐ запрос данных ┌───────┐
│ View │ ◄─────────────────── │ ViewModel │ ──────────────► │ Model │
│ (тупая)│ ── действия (события) ─►│ (state) │ ◄─── данные ──── │(repo) │
└────────┘ └───────────┘ └───────┘
- View — тупой рендер — берёт готовое состояние и рисует; никакой бизнес-логики, только «показать то, что дали».
- ViewModel — держатель состояния — переживает поворот экрана (её создаёт
ViewModelStoreOwner, а не пересоздаёт вместе с Activity). - Model — репозитории, БД, сеть; ViewModel обращается к ним, а не View напрямую.
⚠️ Частая ошибка: хранить View, Activity или Context в поле ViewModel. ViewModel живёт дольше View — после поворота ссылка указывает на уничтоженную Activity, и это утечка памяти. Нужен Context — берите AndroidViewModel.getApplication() или инжектите @ApplicationContext.
Из чего состоит стек Retrofit + OkHttp и за что отвечает каждый слой?
Из чего состоит стек Retrofit + OkHttp и за что отвечает каждый слой?
Короткий ответ: Retrofit — верхний, декларативный слой: превращает Kotlin-интерфейс с аннотациями в HTTP-запросы и парсит ответ через Converter. OkHttp под ним — сам HTTP-клиент: сокеты, пул соединений, кэш, интерцепторы, таймауты, повторы. Retrofit без OkHttp не работает — это его транспорт.
Подробно:
┌─────────────────────────────────────────┐
│ ApiService (interface + @GET/@POST) │ ← ваш код
├─────────────────────────────────────────┤
│ Retrofit: аннотации → Request, │
│ Converter (JSON ↔ data class) │
├─────────────────────────────────────────┤
│ OkHttp: interceptors, connection pool, │
│ cache, timeouts, TLS, retry │
├─────────────────────────────────────────┤
│ Socket / сеть │
└─────────────────────────────────────────┘
- Retrofit — знает про
suspendи возвращает готовый data class; сам JSON не парсит. - Converter — kotlinx.serialization / Moshi / Gson; именно он делает JSON ↔ объект.
- OkHttp — вся сетевая механика; один
OkHttpClientна приложение, чтобы пул и кэш переиспользовались. - CallAdapter — поддержка
suspend-функций из коробки.
⚠️ Частая ошибка: создавать новый OkHttpClient/Retrofit на каждый запрос. Тогда теряются пул соединений и кэш; клиент должен быть синглтоном на всё приложение.
Готовы закрепить навсегда?
Первая сессия — меньше минуты. Ваше будущее «я» на собеседовании скажет спасибо.
Вопросы об этом направлении
Как готовиться к собеседованию на «Android-разработчик»?
Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Android-разработчик» в RecallDeck даёт 161+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2) ровно перед тем, как вы забудете — чтобы на собеседовании ответы были под рукой.
Какие темы охватывает направление «Android-разработчик»?
Направление «Android-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.
Помогает ли интервальное повторение в подготовке к «Android-разработчик»?
Да. Активно вспоминать ответ и честно себя оценивать — куда прочнее для памяти, чем перечитывать заметки. RecallDeck планирует каждую карту «Android-разработчик» так, чтобы она вернулась перед моментом забывания: ежедневных повторений становится меньше, а знания держатся.
Направление «Android-разработчик» бесплатное?
Да — направление «Android-разработчик» и полный планировщик SM-2 бесплатны, с 20 новыми картами в день. Войдите через GitHub, и прогресс синхронизируется с аккаунтом. RecallDeck Pro ($5/мес или $29/год) поднимает дневной лимит и добавляет блиц-режим.