Android | Михаил Белый

Android | Михаил Белый 

Все про Android

43subscribers

46posts

goals1
$14.67 of $1 321 raised
Поплыву на остров Ко Мадсум кормить диких кабанчиков

Топ-100 вопросов с Android-собеседований

Статья содержит список из 100 самых часто задаваемых вопросов на собеседованиях для Android-разработчиков.

Android

Из каких основных компонентов состоит Android-приложение?
Android-приложение состоит из четырех компонентов: Activity, Service, BroadcastReceiver и ContentProvider. Приложение активно, пока работает хотя бы один из них.
В чем разница между регистрацией BroadcastReceiver в манифесте и его созданием в коде?
BroadcastReceiver в манифесте работает всегда, даже если приложение закрыто. В коде – только при запущенном приложении.
Как выглядит жизненный цикл Activity?
onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
Какие существуют launch modes у Activity?
• standard – каждый запуск создаёт новый экземпляр Activity.
• singleTop – новый экземпляр создаётся только если Activity не на вершине стека.
• singleTask – существует один экземпляр в стеке, используется старый, если он есть.
• singleInstance – создаётся в отдельном стеке, один экземпляр на приложение.
С чем связаны ограничения на запуск сервисов в Android?
С оптимизацией потребления ресурсов, улучшением производительности и экономией заряда батареи устройства.
В чем разница между обычным Service и Bound Service?
Service работает в фоне без взаимодействия. Bound Service предоставляет интерфейс для связи и вызова методов из других компонентов.
Почему рекомендуется использовать Parcelable вместо Serializable?
Parcelable быстрее и эффективнее в Android – его лучше использовать для передачи данных между компонентами. Serializable проще, но медленнее из-за рефлексии.
Что происходит в Android между нажатием на иконку приложения и вызовом метода Application.onCreate?
При нажатии на иконку система форкает процесс через Zygote, загружает ресурсы, создаёт объект Application, затем вызывает onCreate().
Какие приоритеты процессов существуют в Android?
• Foreground Process – активные, не убиваются.
• Visible Process – видимые, но неактивные, могут быть убиты.
• Service Process – фоновые службы, убиваются последними.
• Background Process – невидимые, убиваются первыми.
• Empty Process – неиспользуемые.
В чем разница между Application Context и Activity Context?
Application Context живёт всё время работы приложения – используется для глобальных объектов. Activity Context привязан к конкретной Activity – нужен для работы с UI, диалогами и запуска Activity.
В чем различие между Intent и PendingIntent?
Intent используется для немедленного выполнения действий. PendingIntent передаёт действие другому приложению, чтобы оно выполнило его от имени вашего приложения с вашими правами.
Какие ограничения есть у Bundle?
У Bundle нет строгого ограничения, но размер лучше не превышать 1 MB – это может вызвать ошибки. Поддерживаются примитивы, строки, Parcelable, Serializable, массивы и коллекции.
Какие способы сохранения состояния доступны в Android?
• onSaveInstanceState – сохраняет временное состояние при уничтожении Activity.
• ViewModel – сохраняет данные при смене конфигурации.
• SharedPreferences – хранит простые данные ключ-значение между сессиями.
• DataStore – современный способ хранения настроек и данных ключ-значение.
• Room – управляет структурированными данными в SQLite.
• Files – хранит данные в виде файлов во внутреннем или внешнем хранилище.
Какие способы безопасного хранения данных есть в Android?
• EncryptedSharedPreferences – для паролей и конфиденциальной информации.
• SQLite шифрованием – SQLCipher для защиты баз данных SQLite.
• Файлы с шифрованием – шифровать файлы с помощью алгоритмов, таких как AES, перед их сохранением.
• Keystore – хранить криптографические ключи в Android Keystore для безопасного доступа.
• ContentProvider – контролировать доступ к данным и обеспечивать их безопасность через разрешения.
Какие методы обеспечивают безопасность сетевых запросов в Android?
• Использовать HTTPS для шифрования данных.
• Настроить SSL pinning для проверки сертификатов.
• Применять аутентификацию (например, OAuth) для защиты API.
• Шифровать данные на устройстве и при передаче.
• Ограничить доступ через разрешения.
• Использовать защищённые библиотеки (например, Retrofit).
Как уменьшить размер APK?
• Использовать ProGuard или R8 для минификации и обфускации кода.
• Удалить неиспользуемые ресурсы с помощью resConfigs.
• Сжимать картинки и использовать формат WebP.
• Разделить APK на версии для разных архитектур с abiFilters.
• Динамически загружать модули (Dynamic Delivery).
• Оптимизируйте зависимости, исключая избыточные библиотеки.
Для чего используется атрибут targetSdk?
Указывает уровень API, для которого приложение оптимизировано, чтобы использовать новые функции и улучшения, сохраняя совместимость со старыми версиями Android.
Зачем у фрагментов введено разделение на onDestroy(), onDestroyView() и onDetach()?
• onDestroyView() – очищает ресурсы, связанные с View.
• onDestroy() – освобождает остальные ресурсы.
• onDetach() – отсоединяет фрагмент от Activity.
В чем разница между методами add и replace при работе с фрагментами?
add() добавляет новый фрагмент поверх текущего, сохраняя его состояние. replace() удаляет текущий фрагмент и добавляет новый, запуская полный жизненный цикл.
Для чего используется метод commitAllowingStateLoss()?
Выполняет транзакцию, даже если состояние Activity потеряно, предотвращая исключение при коммите.
Как работает DiffUtil в RecyclerView?
DiffUtil сравнивает старые и новые данные, вычисляет разницу и сообщает RecyclerView, какие элементы вставить, удалить или обновить. Использует алгоритмы наименьших различий и наибольшей общей подпоследовательности, что повышает производительность и устраняет мерцание.
Как устранить лаги при прокрутке RecyclerView?
• Избегать тяжёлых операций в onBindViewHolder.
• Использовать VectorDrawable для изображений.
• Минимизировать вызовы notifyDataSetChanged.
• Настроить DiffUtil для оптимизации обновлений.
• Применять RecycledViewPool для вложенных списков
• Настроить setHasFixedSize, setHasStableIds, setItemViewCacheSize.
Как выглядит жизненный цикл View?
• onAttachToWindow – прикрепление View к окну.
• onMeasure – определение размеров View и дочерних элементов.
• onLayout – установка размеров и позиций дочерних элементов.
• onDraw – отрисовка содержимого View.
• onDetachedFromWindow – открепление View от окна.
Для чего используется метод invalidate() у View?
Помечает View для перерисовки, вызывая onDraw() для обновления её внешнего вида.
Что делает метод requestLayout() у View?
Инициирует перерасчет размеров и перерисовку View, вызывая onMeasure() и onLayout().

Jetpack

Как ViewModel сохраняется при пересоздании Activity?
ViewModel сохраняется в ViewModelStore и при пересоздании Activity извлекается из него, предотвращая повторное создание.
Что делает Dagger при сборке проекта?
Dagger генерирует фабрики зависимостей, строит граф и создаёт код для управления ими на основе аннотаций @Inject, @Module, @Component.
В чем разница между компонентом и сабкомпонентом в Dagger?
Компонент предоставляет зависимости самостоятельно. Сабкомпонент наследует зависимости и область (scope) родительского компонента.
Могут ли сабкомпоненты Dagger знать друг о друге?
Сабкомпоненты не знают друг о друге напрямую – они взаимодействуют через родительский компонент.
В чем разница между аннотациями @Binds и @Provides?
@Binds связывает интерфейс с реализацией через абстрактный метод без создания объекта. @Provides создаёт экземпляры через метод с логикой.

Compose

Как устроен жизненный цикл @Composable-функции в Compose?
• Composition – строит UI, создавая иерархию и состояние.
• Recomposition – обновляет только изменённые части UI при изменении состояния.
• Disposal – удаляет элемент из UI и очищает его ресурсы.
Какие стадии отрисовки фрейма есть в Compose?
• Composition – вызов Composable-функций для создания или обновления UI.
• Layout – вычисление размеров и позиций компонентов.
• Drawing – отрисовка элементов на экране.
В чем разница между remember и rememberSaveable в Compose?
remember сохраняет состояние между рекомпозициями. rememberSaveable сохраняет его при пересоздании, включая смену конфигурации.
Какие типы в Compose считаются стабильными?
Типы с @Stable, неизменяемые (val), встроенные (Int, String) и data class с val-полями.
Зачем нужны аннотации @Stable и @Immutable в Compose?
@Immutable указывает, что объект неизменяем, для оптимизации рендеринга. @Stable обозначает контролируемые изменения, чтобы Compose эффективно отслеживал их.
Какие виды сайд-эффектов существуют в Compose?
• SideEffect – выполняет действия после завершения @Composable.
• LaunchedEffect – запускает корутины, перезапуская их при изменении ключа.
• DisposableEffect – очищает ресурсы при изменении ключа или отмене.
Что компилятор неявно передает во все Composable-функции?
Компилятор неявно передаёт в @Composable-функции объект Composer для управления состоянием и рекомпозицией.
Что сделать, если LazyColumn лагает при прокрутке?
• Упростить и уменьшить элементы.
• Использовать remember для кэширования.
• Применить key для предотвращения пересчётов.
• Исключить тяжёлые операции из item или itemContent.

Kotlin

В чем разница между val и const val в Kotlin?
val инициализируется во время выполнения. const val инициализируется на этапе компиляции, поддерживает только примитивы и строки, и объявляется только в корне или объектах.
Что представляет собой функция высшего порядка в Kotlin?
Функция высшего порядка принимает функцию как аргумент или возвращает её как результат.
Для чего используется тип Nothing в Kotlin?
Nothing обозначает отсутствие значения – используется для функций, которые никогда не возвращаются (например, бросают исключения), улучшая типизацию и логику.
Для чего используется companion object в Kotlin?
Для создания статических членов класса, доступных без создания экземпляра. Подходит для фабрик, констант и реализации интерфейсов.
Что такое inline-функции в Kotlin?
inline-функции вставляют своё тело вместо вызова при компиляции, уменьшая накладные расходы и избегая создания лишних объектов, особенно с лямбдами.
Для чего используются noinline и crossinline в inline-функциях?
noinline запрещает встраивание лямбды, позволяя передавать её как параметр. crossinline предотвращает возврат из лямбды через return, обеспечивая корректный поток выполнения.
Почему reified позволяет получить тип объекта?
reified сохраняет тип дженерика во время выполнения, так как в inline-функциях тип передаётся напрямую, избегая стирания на этапе компиляции.
Как определить, что функцию нужно инлайнить?
Инлайнить стоит, если функция маленькая, часто вызывается или принимает лямбды – это снижает накладные расходы и избегает создания объектов.
Что будет, если сигнатура extension-функции совпадет с методом класса?
При совпадении сигнатуры вызовется метод класса.
Как устроена иерархия исключений в Kotlin?
Исключения в Kotlin наследуются от Throwable и делятся на Error (необрабатываемые) и Exception (обрабатываемые).
Что такое анонимный класс в Kotlin?
Это класс без имени, создаваемый для реализации интерфейсов или абстрактных классов на месте, упрощая переопределение методов.
В чем разница между inner и обычным вложенным классом?
inner class связан с экземпляром внешнего класса и имеет доступ к его полям. Обычный вложенный класс существует независимо и не имеет такого доступа.
В чем разница между sealed class и enum class?
sealed class ограничивает набор подклассов и поддерживает наследование. enum class представляет фиксированный набор констант без наследования. enum class подходит для состояний, sealed class – для значений.
Что такое data class?
Класс, который хранит данные и автоматически генерирует equals(), hashCode(), toString(), copy() и componentN() для упрощения работы с объектами.
Какие риски связаны с объявлением лямбды в первичном конструкторе data-класса?
Лямбда в конструкторе data-класса делает экземпляры неравными при сравнении, даже с одинаковыми параметрами, так как сравниваются ссылки, а не логика, нарушая контракт equals().

Collections

Почему в Kotlin коллекции делятся на mutable и immutable?
Коллекции делятся на mutable и immutable для предсказуемости и потокобезопасности: mutable изменяются, immutable предотвращают неожиданные изменения данных.
В чем разница между Collection и Sequence?
Collection выполняет операции сразу, сохраняя промежуточные результаты в памяти. Sequence обрабатывает элементы лениво, экономя память и время, особенно при последовательных операциях.
В чем разница между ArrayList и LinkedList?
ArrayList основан на массиве: быстрый доступ O(1), медленные вставка и удаление O(n). LinkedList – двусвязный список: вставка и удаление O(1), доступ по индексу O(n).
Какой пошаговый процесс добавления объекта в HashMap?
• Ключ проверяется на null. Если null, объект помещается в корзину с индексом 0, хеш = 0.
• Вычисляется хешкод ключа.
• Определяется номер корзины (бакета) с учётом хешкода и размера таблицы.
• Создаётся Node, который помещается в корзину как первый элемент.
• Если корзина уже содержит элементы, добавляется в конец списка.
• При коллизии хешкодов используется equals – равные элементы перезаписываются, неравные добавляются в конец списка.
• Если совпадают и хешкод, и equals, элемент перезаписывается.
Как объекты хранятся внутри бакета в HashMap?
В бакете объекты хранятся как связанный список или сбалансированное дерево (при множестве коллизий). Каждый элемент – это пара ключ-значение.
Что такое коллизия в HashMap?
Коллизия возникает, когда два элемента имеют одинаковый хэш-код и попадают в один бакет. Разные ключи хранятся как цепочка, одинаковые заменяют друг друга.
Гарантирует ли HashSet порядок элементов?
HashSet не гарантирует порядок. Для сохранения порядка добавления используется LinkedHashSet.
Какие есть способы обеспечить потокобезопасность при работе с коллекциями?
Для потокобезопасности можно использовать synchronized-коллекции (synchronizedList, synchronizedSet), ConcurrentHashMap, CopyOnWriteArrayList – они предотвращают ошибки синхронизации и гонки.

Coroutines

Какие есть способы синхронизации корутин?
• Mutex – блокирует доступ к ресурсу.
• Channels – передают данные между корутинами безопасно.
• Dispatcher.limitedParallelism(1) – ограничивает выполнение корутин одним потоком.
• Atomic – обновляет значения безопасно, без блокировок.
Из чего состоит контекст корутины?
• CoroutineDispatcher – определяет поток или диспетчер.
• CoroutineName – имя для отладки.
• CoroutineExceptionHandler – обрабатывает исключения.
• Job – управляет жизненным циклом.
• SupervisorJob – гибкое управление ошибками и отменой.
Как работает механизм приостановки (suspension) в корутинах?
suspend-функция приостанавливает корутину, освобождая поток. Состояние сохраняется, а выполнение возобновляется после завершения асинхронной операции, без блокировки потока.
В чем разница между launch и async?
launch запускает корутину без возврата результата, возвращая Job. async возвращает Deferred для получения результата через await.
Почему в Dispatchers.Default одновременно выполняется до 4 операций (на 4 ядрах), а в Dispatchers.IO до 64?
Dispatchers.Default ограничен числом ядер (обычно 4 потока) для интенсивных операций. Dispatchers.IO поддерживает до 64 потоков, создавая псевдопараллельность для блокирующих задач.
Что произойдет с корутиной при переключении с Dispatcher.Default на Dispatcher.IO?
При переключении с Dispatcher.Default на Dispatcher.IO корутина требует переключения контекста, реальный поток выполнения может остаться тем же. Это дешевле, чем создание нового потока.
Что произойдет, если выполнять сетевые запросы на Dispatcher.Default в Kotlin?
Сетевые запросы на Dispatcher.Default блокируют потоки, снижая производительность, так как он предназначен для CPU-задач. Для I/O операций лучше использовать Dispatcher.IO.
Как обрабатывать исключения в корутинах?
• try-catch – для локальной обработки исключений в корутине.
• CoroutineExceptionHandler – для необработанных исключений.
• SupervisorJob – изолирует исключения дочерних корутин, предотвращая их распространение.
Как ведет себя корутина при вызове метода cancel?
Корутина помечается как Cancelled и прекращает выполнение при первой проверке состояния отмены.
Какие виды Flow существуют?
• Flow – асинхронный поток данных.
• StateFlow – поток, хранящий последнее значение.
• SharedFlow – поток с множественными подписчиками.
В чем разница между SharedFlow и StateFlow?
• StateFlow – сохраняет текущее значение и передаёт его новым подписчикам.
• SharedFlow – не сохраняет значения и просто транслирует их подписчикам без истории.
Какие параметры существуют у SharedFlow?
• replay – число последних значений для новых подписчиков.
• extraBufferCapacity – дополнительные значения в буфере при нагрузке.
• onBufferOverflow – поведение при переполнении буфера (DROP_OLDEST, SUSPEND).
Для чего используются каналы в Kotlin?
Каналы используются для безопасной и асинхронной передачи данных между корутинами, обеспечивая синхронизацию и избегая гонок.
Какие типы каналов существуют в Kotlin?
• Rendezvous – без буфера, блокирует отправителя и получателя до обмена.
• Buffered – с буфером, позволяет отправлять несколько элементов без блокировки.
• Conflated – хранит только последнее значение, удаляя предыдущие.

Java

Как устроена модель памяти в JVM?
Модель памяти JVM включает:
• Heap – хранит объекты.
• Stack – хранит локальные переменные и вызовы методов.
• Method Area – содержит байт-код и метаданные.
• Синхронизация для потоков и сборщик мусора для управления памятью.
Как в Java обрабатываются строки с одинаковыми значениями?
Строки с одинаковыми значениями кэшируются в строковом пуле. При создании через литерал JVM ищет строку в пуле и возвращает ссылку, если она уже существует.
В чем разница между проверенными и непроверенными исключениями в Java?
Проверенные (checked) исключения требуют обработки или объявления через throws. Непроверенные (unchecked), наследующие RuntimeException, можно не обрабатывать.
Какой есть контракт между equals и hashCode в Java?
Если переопределён equals, нужно переопределить hashCode, чтобы обеспечить корректную работу коллекций, таких как HashSet и HashMap, которые используют хэш-коды для быстрого поиска объектов.
Как работает сборщик мусора (GC) в Java?
Сборщик мусора автоматически освобождает память, удаляя объекты без ссылок. Он сохраняет активные объекты и очищает неиспользуемые.
Что вызывает запуск сборщика мусора в Java?
GC запускается при нехватке памяти, вызове System.gc() или достижении порога использования памяти при создании новых объектов.
В чем разница между WeakReference и SoftReference?
WeakReference удаляется при ближайшей сборке мусора. SoftReference удаляется, когда требуется память, что полезно для кеширования.
Как можно избежать утечек памяти в Android?
• Избегать долгоживущих ссылок на Context.
• Использовать WeakReference для долгоживущих объектов.
• Очищать ресурсы в onDestroy().
• Вовремя отписывать слушатели.
Как сборщик мусора может заставить UI тормозить?
Сборщик мусора может замедлить UI из-за механизма «stop-the-world», когда приложение приостанавливается для очистки памяти, что влияет на отклик интерфейса.

Многопоточность

В чем разница между асинхронностью и параллельностью в работе потоков?
Асинхронность приостанавливает задачи без блокировки потока, а параллельность выполняет задачи одновременно на разных потоках.
Какие методы синхронизации потоков существуют в Java?
• synchronized – блокирует доступ к методу или блоку для других потоков.
• Lock – явное управление блокировками через lock() и unlock().
• Atomic-классы (например, AtomicInteger) – неблокирующие операции для атомарных данных.
• volatile – гарантирует видимость изменений между потоками.
• Семафоры, CountDownLatch, CyclicBarrier, ReadWriteLock – для координации потоков и управления доступом.
Как решается доступ к занятию ресурса, если его одновременно запрашивают несколько потоков?
Через синхронизацию – один поток получает доступ, остальные ждут.
Как пробудить поток, находящийся в состоянии ожидания ресурса?
Вызвать notify() или notifyAll() на объекте блокировки.
Как избежать ситуации взаимной блокировки (deadlock) в многопоточных приложениях?
Упорядочивать захват ресурсов, избегать циклических зависимостей и использовать тайм-ауты для блокировок.
Как предотвратить возникновение Race Condition?
Использовать синхронизацию через synchronized, блокировки ReentrantLock, атомарные переменные или конструкции типа CountDownLatch и CyclicBarrier.
Почему ThreadPool эффективнее, чем использование цикла с new Thread для создания потоков?
ThreadPool эффективнее, так как повторно использует потоки, снижая затраты на создание и уничтожение, улучшая производительность и управление задачами.
Как работает volatile в Java?
volatile гарантирует видимость последнего значения переменной для всех потоков, предотвращая кэширование и обеспечивая доступ к основной памяти, но не обеспечивает атомарности операций.
Зачем используются атомарные переменные в многопоточности?
Атомарные переменные обеспечивают безопасное взаимодействие между потоками без блокировок, предотвращая гонки данных и улучшая производительность.
В чем разница между постфиксным a++ и префиксным ++a инкрементом?
• a++ – сначала возвращает текущее значение, потом увеличивает на 1.
• ++a – сначала увеличивает на 1, потом возвращает новое значение.

Архитектура

Какие принципы включает SOLID?
• S – у класса должна быть одна ответственность.
• O – классы открыты для расширения, закрыты для модификации.
• L – подклассы заменяемы базовыми классами.
• I – интерфейсы должны быть узкими и специализированными.
• D – зависимости должны зависеть от абстракций, а не реализаций.
Что представляет собой чистая архитектура?
Чистая архитектура разделяет код на слои, снижая зависимости и повышая тестируемость:
• Presentation – UI и логика представления (Activity, Fragment, ViewModel).
• Domain – бизнес-логика (UseCase, Interactor).
• Data – работа с данными (репозитории, API, базы данных).
В чем разница между архитектурными паттернами MVVM и MVI?
• MVVM – разделяет логику на Model, View и ViewModel, где ViewModel управляет данными и UI, не завися от View.
• MVI – использует единый источник истины, передавая данные через Intent от пользователя к Model, а затем обновляет View.
Какие существуют виды паттернов проектирования?
• Порождающие – для создания объектов (Singleton, Factory Method, Builder).
• Структурные – для организации взаимодействий (Adapter, Decorator, Facade).
• Поведенческие – для управления поведением (Observer, Command, Strategy).

Алгоритмы

Как определить пространственную сложность алгоритма?
Пространственная сложность – это объём памяти, используемой алгоритмом, включая входные данные и вспомогательные структуры. Оценивается относительно размера входа, например, O(n) для массива из n элементов.
Зачем разработчику учитывать сложность алгоритмов при написании кода?
Учитывать сложность нужно для выбора эффективных решений, прогнозирования времени работы и потребления ресурсов, а также предотвращения проблем с производительностью на больших данных.
Новые вопросы добавляются в роадмап.
Subscription levels1

Жалкий детский уровень

$1.33 per month
• Бесконечный респект и признательность 
• Ранний доступ к видео и воркшопам
• Отдельный топик в телеграм-чате с записями реальных Android-собеседований
• Отдельный топик с автоматическими новостями про Android-разработку
+ chat
Go up