Android-разработчик
80 задач. Условие и варианты ответа открыты всем; проверка, подсказка и разбор — в клубе.
Kotlin и жизненный цикл Android
- Безопасный вызов и элвис-оператор: что напечатает код
- val у изменяемой коллекции: скомпилируется ли добавление элемента
- Поворот экрана: что станет со счётчиком в поле Activity
- Подписка во фрагменте с this вместо владельца жизненного цикла View
- Значение из Java-метода без аннотаций присвоено в non-null тип
- Синглтон хранит Context экрана
- Форма пустая после возврата из фона, хотя поворот переживала
- Краш при показе диалога из колбэка, пришедшего после сворачивания
Корутины и Flow
- Запрос запущен в глобальной области, а экран закрыли
- Thread.sleep внутри корутины на главном потоке
- Холодный Flow без подписчика
- try/catch снаружи launch не ловит ошибку запроса
- Два async с немедленным ожиданием: сколько займёт загрузка
- Прогресс загрузки доходит до подписчика не полностью
- Сбор потока продолжается, когда экран ушёл в фон
- job.cancel не останавливает тяжёлый цикл
Jetpack Compose и состояние экрана
- Счётчик в Compose не растёт при нажатии
- Порядок модификаторов: где окажется жёлтый фон
- Column со скроллом на 5000 элементов
- Отметка чекбокса переезжает на другой элемент списка
- Эффект с постоянным ключом при смене идентификатора
- Добавление в список внутри потока состояния не обновляет экран
- После поворота экрана приложение снова уходит на экран успеха
- Кнопка «наверх» вызывает перерисовку всего экрана при прокрутке
Слой данных, DI и релиз
- Синхронный запрос к Room на главном потоке
- Ошибка 500 не попала в обработку ошибок
- ViewModel сама создаёт клиент сети
- После обновления приложение падает на старте только у части пользователей
- Границы слоёв в сценарии использования
- В релизной сборке поля модели приходят пустыми
- Тест ViewModel с корутинами то проходит, то нет
- Офлайн-данные не уходят на сервер после закрытия приложения
Kotlin: классы, коллекции и идиомы
- В Set избранного оказались два одинаковых товара
- После добавления состояния Empty сборка упала на when
- Фрагмент падает с «lateinit property adapter has not been initialized»
- Аргументы фрагмента собрали через let — сборка не проходит
- Поиск первой доступной цены вызывает расчёт миллион раз
- Функция-расширение для наследника не вызывается через переменную базового типа
- Два потока одновременно обращаются к базе, объявленной через by lazy
- Обобщённый разбор JSON не компилируется на T::class.java
- return@forEach в проверке полей формы: что напечатает код
- Java-экран не видит Kotlin-метод аналитики с параметром по умолчанию
- Функция логирования принимает List<Any>, но не MutableList<Any>
- Фильтр изменили после добавления в HashSet — contains вернул false
Сеть: Retrofit, OkHttp и сериализация
- В 30 методах API вручную передаётся заголовок Authorization
- Приложение падает при создании Retrofit: baseUrl must end in /
- Запросы к тестовому серверу по http падают с CLEARTEXT communication not permitted
- С эмулятора localhost:8080 отвечает «Connection refused», а в браузере компьютера — работает
- В logcat релизной сборки видны токены и телефоны пользователей
- Отчёт, который сервер готовит 25 секунд, падает у клиента с SocketTimeoutException
- Бэкенд добавил поле promo — все экраны каталога показывают ошибку
- NullPointerException в поле String, которое по типу не может быть null
- Ревьюер требует обернуть suspend-вызов Retrofit в withContext(Dispatchers.IO)
- Главный экран делает 5 запросов — сервер получает 5 обновлений токена и разлогинивает
- Чат перестаёт получать сообщения после переключения с Wi-Fi на мобильную сеть
- После внедрения автоповторов у части пользователей заказы создаются дважды
MVVM, MVI и многомодульность
- ViewModel хранит ссылку на TextView, чтобы сразу выставить текст
- На экране одновременно крутится загрузка и висит текст ошибки
- Фрагмент сам записал значение в состояние ViewModel
- Три экрана по-разному решают, брать каталог из базы или из сети
- Модуль app не видит класс OkHttpClient из модуля core:network
- Корзина открывает каталог, каталог открывает корзину — Gradle находит цикл
- Для теста сценария расчёта скидки понадобился эмулятор
- Быстрые нажатия «+» в корзине иногда теряют одно добавление
- Приложение падает при сворачивании экрана с TransactionTooLargeException
- Бэкенд переименовал price в price_kopecks — правки понадобились в 40 файлах
- После выхода и входа под другим аккаунтом видна корзина прошлого пользователя
- На третьем шаге оформления заказа адрес с первого шага пустой
Тестирование: JUnit, MockK, Espresso и Compose
- Юнит-тест валидатора падает с «Method isEmpty in android.text.TextUtils not mocked»
- Тест на Espresso положили в src/test — он не запускается без устройства
- 200 Espresso-тестов идут на CI 40 минут и проверяют в основном валидацию форм
- MockK: every { repo.loadUser(1) } не компилируется
- После рефакторинга корзины сломались 30 тестов, хотя приложение работает
- UI-тест ждёт загрузку через Thread.sleep(3000) и падает на CI раз в пять запусков
- Как проверить, что ответ 401 превращается в экран входа, не поднимая бэкенд
- Compose-тест: onNodeWithText("Купить") находит два узла
- Неправильная сортировка истории заказов прошла все тесты с моком DAO
- Тест срока промокода был зелёным в день написания и упал на следующий
- UI-тесты с Hilt ходят в боевой API, потому что модуль сети не подменён
- Покрытие корзины 92%, а ошибка в расчёте скидки дошла до пользователей
