Направление

Подготовка к собеседованию — Android-разработчик

Колода из 161+ карточек с вопросами для собеседования по направлению «Android-разработчик» — по темам и уровню сложности, с повторениями по вашим оценкам. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).

161 карточка10 тем
Посмотреть цены и начать

Новым подписчикам месяца или года может быть доступно 7 дней бесплатно. Условия и сумму подтвердит страница оплаты.

С чего начать

Нужны основы Kotlin и опыт создания небольшого Android-приложения. В общих алгоритмах есть примеры на Python; потренируйтесь переносить эти идеи в Kotlin.

Первый проход: Kotlin и система типов → Корутины и Flow. Начните с базовых вопросов в этих модулях, затем продолжайте по плану. К сложным и senior-вопросам возвращайтесь по требованиям вакансии; все карточки доступны с самого начала.

Общие темы могут входить в несколько направлений и сохраняют одну историю повторений. План ниже отмечает общие основы и профильные модули; выбирайте глубину под свою вакансию.

Что внутри

Все темы направления, сгруппированные так, как вы будете их учить.

Kotlin и система типов

11 карточек

Профильный модуль

Kotlin и типы

Корутины и Flow

12 карточек

Профильный модуль

Корутины и Flow

Компоненты и жизненный цикл

10 карточек

Профильный модуль

Компоненты и жизненный цикл

UI: Views и Jetpack Compose

11 карточек

Профильный модуль

Views и Compose

Архитектура Android-приложений

10 карточек

Профильный модуль

Архитектура

Сеть и хранение данных

10 карточек

Профильный модуль

Сеть и хранение

Производительность и внутреннее устройство

10 карточек

Профильный модуль

Производительность

Тестирование и инструменты

9 карточек

Профильный модуль

Тестирование и инструменты

Основы CS

43 карточки

Общие основы

Структуры данных и алгоритмы

Поведенческое интервью

35 карточек

Общие основы

Поведенческое интервью

Примеры вопросов

Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.

Чем val отличается от var и делает ли val объект неизменяемым?

Короткий ответ: var позволяет повторное присваивание, val — нет. Ни один вариант не делает объект неизменяемым. List<T> — интерфейс только для чтения: другая ссылка всё ещё может изменить базовую коллекцию.

val backing = mutableListOf(1, 2)
val view: List<Int> = backing
backing.add(3)
println(view) // [1, 2, 3]: read-only не значит immutable
val snapshot = backing.toList()
backing.add(4)
println(snapshot) // [1, 2, 3]

Подробно:

  1. val с хранимым значением сохраняет ссылку. Свойство с кастомным getter может возвращать другое значение при каждом обращении: val now: Long get() = System.currentTimeMillis().
  2. toList() создаёт отдельную поверхностную копию: структурные изменения исходной коллекции на неё не влияют, но изменяемые объекты-элементы остаются общими. Глубокая неизменяемость требует также неизменяемых элементов и контроля владения.
  3. const val — константа времени компиляции на верхнем уровне или внутри object/companion object, с допустимым примитивным значением или String.

Важно: val вместе с List запрещает повторное присваивание и запись через этот интерфейс, но не гарантирует неизменяемость всего графа объектов.

Источники: Коллекции Kotlin, копирование коллекций.

Что такое корутина и чем 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
}
  1. Приостановка ≠ блокировка — delay возвращает управление диспатчеру, Thread.sleep удерживает поток.
  2. Лёгкость — корутина это объект в куче (continuation + стейт), а не стек ~1 МБ, как у потока.
  3. Кооперативность — корутина уступает поток только в точках приостановки (suspension points).

⚠️ Частая ошибка: «саспенд-функция выполняется в фоновом потоке». Нет: suspend сам по себе поток не переключает — где выполняться, решает диспатчер.

Назови полный жизненный цикл Activity — какие колбэки и зачем нужен каждый?

Короткий ответ: Три «поднимающих» колбэка — onCreate → onStart → onResume — выводят экран к пользователю; три «опускающих» — onPause → onStop → onDestroy — убирают. onRestart вызывается, когда остановленная Activity снова возвращается на экран.

Подробно:

     onCreate()    ← создан: setContentView, init, чтение savedInstanceState
        │
     onStart()     ← стал видимым
        │
     onResume()    ← на переднем плане, принимает ввод
        │
   [ RESUMED — работает ]
        │
     onPause()     ← потерял фокус (частично перекрыт)
        │
     onStop()      ← полностью не виден  ──onRestart()→onStart() при возврате
        │
     onDestroy()   ← уничтожен (finish или нехватка памяти)
  1. onCreate — единственный обязательный; здесь инфляция layout, инициализация, восстановление из savedInstanceState.
  2. onStart / onStop — граница видимости: регистрируем и снимаем то, что нужно только видимому экрану.
  3. onResume / onPause — граница фокуса и ввода; onPause обязан быть коротким — следующий экран не покажется, пока он не вернётся.
  4. 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 не читает → пропустится
    }
}
  1. Триггер — не «любое изменение», а запись в snapshot-состояние, которое читалось в конкретной composable. Compose отслеживает чтения и инвалидирует ровно нужные scope'ы.
  2. Оптимистична — если во время рекомпозиции состояние снова поменялось, текущий проход отбрасывается и стартует заново.
  3. Неупорядочена и может идти параллельно — порядок выполнения соседних composable не гарантирован; нельзя закладываться на side-effect'ы прямо в теле.

⚠️ Частая ошибка: обычная var без mutableStateOf — это не state; её изменение Compose не видит и рекомпозицию не запустит, UI «застынет».

Что такое MVVM и почему ViewModel не должна ссылаться на View или Context?

Короткий ответ: MVVM делит экран на три роли: Model (данные и логика), View (Activity/Fragment/Composable — только рисует и передаёт действия) и ViewModel (держит состояние и переживает пересоздание View). ViewModel не знает про конкретную View — она лишь публикует состояние, на которое View подписывается.

Подробно:

┌────────┐  подписка на state   ┌───────────┐  запрос данных  ┌───────┐
│  View  │ ◄─────────────────── │ ViewModel │ ──────────────► │ Model │
│ (тупая)│ ── действия (события) ─►│ (state)   │ ◄─── данные ──── │(repo) │
└────────┘                       └───────────┘                 └───────┘
  1. View — тупой рендер — берёт готовое состояние и рисует; никакой бизнес-логики, только «показать то, что дали».
  2. ViewModel — держатель состояния — переживает поворот экрана (её создаёт ViewModelStoreOwner, а не пересоздаёт вместе с Activity).
  3. Model — репозитории, БД, сеть; ViewModel обращается к ним, а не View напрямую.

⚠️ Частая ошибка: хранить View, Activity или Context в поле ViewModel. ViewModel живёт дольше View — после поворота ссылка указывает на уничтоженную Activity, и это утечка памяти. Нужен Context — берите AndroidViewModel.getApplication() или инжектите @ApplicationContext.

Из чего состоит стек 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 / сеть                            │
└─────────────────────────────────────────┘
  1. Retrofit — знает про suspend и возвращает готовый data class; сам JSON не парсит.
  2. Converter — kotlinx.serialization / Moshi / Gson; именно он делает JSON ↔ объект.
  3. OkHttp — вся сетевая механика; один OkHttpClient на приложение, чтобы пул и кэш переиспользовались.
  4. CallAdapter — поддержка suspend-функций из коробки.

⚠️ Частая ошибка: создавать новый OkHttpClient/Retrofit на каждый запрос. Тогда теряются пул соединений и кэш; клиент должен быть синглтоном на всё приложение.

Готовы лучше запоминать?

Посмотрите пример, выберите направление и настройте регулярную практику под свою подготовку.

Вопросы об этом направлении

Как готовиться к собеседованию на «Android-разработчик»?

Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Android-разработчик» в RecallDeck даёт 161+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2), основанному на ваших оценках — чтобы тренировать вспоминание и объяснение. Дополняйте повторения кодингом и пробными собеседованиями.

Какие темы охватывает направление «Android-разработчик»?

Направление «Android-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.

Помогает ли интервальное повторение в подготовке к «Android-разработчик»?

Да. Активное вспоминание и честная самооценка помогают закреплять знания. RecallDeck назначает повторения карт по направлению «Android-разработчик» на основе ваших оценок: знакомые карты возвращаются реже, а сложные получают больше практики.

Можно попробовать направление «Android-разработчик» до оплаты?

Новым подписчикам месячного или годового тарифа может быть доступен пробный период семь дней со всем направлением «Android-разработчик» и всеми функциями. Право на него и сумму подтвердит страница оплаты; при повторной подписке списание может быть сразу. Отмените подписку онлайн до конца пробного периода, чтобы избежать первого списания. У вечного доступа пробного периода нет.

Другие направления