Jetpack Compose
Декларативный UI на Kotlin — чем композиция отличается от императивной системы View, рекомпозиция и что вызывает лишнюю, remember против обычной локальной переменной, Compose Multiplatform и Compose Hot Reload.
7 вопросов
JuniorТеорияОчень частоЧто делает remember, чего не может обычная локальная var в composable?
Что делает remember, чего не может обычная локальная var в composable?
Обычная локальная var заново инициализируется при каждой рекомпозиции и потому ничего не хранит. remember кэширует значение между рекомпозициями; rememberSaveable вдобавок переживает смену конфигурации и смерть процесса, ведь пишет значение в saved-instance Bundle.
Типичные ошибки
- ✗Считать, что обычная локальная
varпереживает рекомпозицию и может хранить состояние UI - ✗Думать, что один
rememberпереживает смену конфигурации и смерть процесса - ✗Полагать, что рекомпозицию запускает запись переменной, а не чтение
State
Уточняющие вопросы
- →Почему
rememberSaveableограничивает типы, которые он может хранить? - →Когда состояние должно жить в
ViewModel, а не вrememberSaveable?
MiddleТеорияОчень частоЧто вызывает рекомпозицию и почему нестабильный параметр делает её хуже?
Что вызывает рекомпозицию и почему нестабильный параметр делает её хуже?
Compose переисполняет composable при изменении читаемого состояния — только те, что его читают, и только это поддерево: рекомпозиция пропускаема. Нестабильный параметр — лямбда, создаваемая каждый кадр, или недоказуемо стабильный тип — ломает пропуск: потомок рекомпозируется зря.
Типичные ошибки
- ✗Думать, что изменение состояния перерисовывает весь экран, а не поддеревья, которые его читают
- ✗Считать, что рекомпозицию запускает запись состояния, а не его чтение
- ✗Передавать новый литерал лямбды каждый кадр и ждать, что потомок всё равно пропустится
Уточняющие вопросы
- →Как компилятор Compose решает, что тип стабилен, без явного
@Stable? - →Почему вынос или
rememberлямбды возвращает потомку способность пропускаться?
JuniorТеорияЧастоЧем декларативный UI в Compose отличается от императивной системы View?
Чем декларативный UI в Compose отличается от императивной системы View?
В Compose UI — это функция состояния: вы описываете экран при данном состоянии, а Compose переисполняет composable, когда это состояние меняется. В системе View вы держите ссылки на виджеты и меняете их на месте, поэтому UI и состояние могут разойтись.
Типичные ошибки
- ✗Думать, что Compose просто оборачивает систему View и всё равно правит виджеты сеттерами
- ✗Считать, что декларативный UI означает пересборку всего экрана каждый кадр
- ✗Полагать, что XML-разметка делает систему View декларативной в том же смысле
Уточняющие вопросы
- →Почему composable обязан быть без побочных эффектов, раз Compose может его переисполнить?
- →Где живёт состояние, если composable не держит изменяемых ссылок на виджеты?
JuniorТеорияЧастоЧем Jetpack Compose отличается от Compose Multiplatform?
Чем Jetpack Compose отличается от Compose Multiplatform?
Jetpack Compose — Android-тулкит UI от Google. Compose Multiplatform — сборка той же модели и того же плагина компилятора от JetBrains для Android, iOS, desktop и веба. Его Android-таргет и есть Jetpack Compose; остальные несут свой рендерер и теряют Android-специфичные API.
Типичные ошибки
- ✗Думать, что Compose Multiplatform — другой UI-фреймворк, у которого лишь совпало имя
- ✗Считать, что Android-специфичные API вроде
Contextдоступны на таргетах iOS и web - ✗Полагать, что Android-таргет Compose Multiplatform обходит Jetpack Compose стороной
Уточняющие вопросы
- →В каком общем source set лежат общие composable для iOS и Android?
- →Чем рисует таргет iOS, если там нет системы View из Android?
MiddleТеорияИногдаЧто делает Compose Hot Reload и на каких таргетах он реально работает?
Что делает Compose Hot Reload и на каких таргетах он реально работает?
Он подставляет изменённый код composable в уже запущенное приложение, сохраняя состояние UI, поэтому правка вёрстки видна без перезапуска. Он стабилен с 1.0 (ноябрь 2025) и идёт с Compose Multiplatform 1.10, но работает только на JVM/desktop — не на Android, iOS или в вебе.
Типичные ошибки
- ✗Утверждать, что Compose Hot Reload работает на Android, а не только на JVM/desktop
- ✗Думать, что он перезапускает приложение, а не сохраняет состояние UI при правке
- ✗Называть его экспериментальным — он стабилен с 1.0 и идёт с Compose Multiplatform 1.10.0
Уточняющие вопросы
- →Какие изменения кода всё равно требуют полного перезапуска вместо hot reload?
- →Почему для превью UI на Android нужен другой инструмент, чем hot reload на desktop?
SeniorДебаггингИногдаВвод в поле поиска подтормаживает — найдите лишнюю рекомпозицию и уберите её
Ввод в поле поиска подтормаживает — найдите лишнюю рекомпозицию и уберите её
Чтение query прямо в OrderScreen рекомпозирует всё его тело на каждое нажатие, а sorted — обычная локальная переменная, поэтому список пересортировывается заново, хотя orders не менялся. Закэшируйте сортировку через remember(orders), а query читайте в наименьшем composable, которому он нужен.
Типичные ошибки
- ✗Считать, что вычисление внутри composable выполняется один раз, а не на каждой рекомпозиции
- ✗Читать состояние на верху экрана и ждать, что рекомпозируется только использующий его потомок
- ✗Считать рекомпозиции бесплатными и смотреть только на стоимость отрисовки кадра
Уточняющие вопросы
- →Когда нужен
derivedStateOf, а не обычныйremember(key)? - →Какой инструмент даёт счётчик рекомпозиций по composable и о чём говорит большое число пропусков?
SeniorДизайнРедкоВаша команда выпускает Android-приложение для управления заказами, целиком написанное на Jetpack Compose: около сорока экранов плюс сканирование камерой, push-уведомления и встроенные платежи. Теперь компания хочет iOS-приложение за два квартала силами одного Android- и одного iOS-инженера. iOS-инженер ждёт нативной навигации и нативных элементов форм на экранах, которыми пользуются чаще всего, а Android-приложение не должно просесть ни по времени сборки, ни по размеру. Нужно решить, будет ли новый общий модуль рисовать UI через Compose Multiplatform или Compose останется только на Android, а у iOS будет свой слой UI. Объясните, что вы положите в общий модуль и что осознанно оставите снаружи, как из общего кода достаются камера, push и платежи, какие экраны (если такие есть) вы бы рисовали общим Compose-UI и что стали бы измерять, чтобы обосновать решение.
Ваша команда выпускает Android-приложение для управления заказами, целиком написанное на Jetpack Compose: около сорока экранов плюс сканирование камерой, push-уведомления и встроенные платежи. Теперь компания хочет iOS-приложение за два квартала силами одного Android- и одного iOS-инженера. iOS-инженер ждёт нативной навигации и нативных элементов форм на экранах, которыми пользуются чаще всего, а Android-приложение не должно просесть ни по времени сборки, ни по размеру. Нужно решить, будет ли новый общий модуль рисовать UI через Compose Multiplatform или Compose останется только на Android, а у iOS будет свой слой UI. Объясните, что вы положите в общий модуль и что осознанно оставите снаружи, как из общего кода достаются камера, push и платежи, какие экраны (если такие есть) вы бы рисовали общим Compose-UI и что стали бы измерять, чтобы обосновать решение.
Сначала выносите слой без платформы — состояние, view models, бизнес-логику: он окупается при любом выборе UI. Общий Compose-UI берите только там, где нативный внешний вид не требование; самые ходовые экраны iOS оставьте нативными. Камера, push и платежи живут за платформенной реализацией. Решайте, замерив долю платформенно-независимой логики.
Типичные ошибки
- ✗Считать, что Android-специфичные API вроде платежей переедут на iOS даром вместе с общим UI
- ✗Видеть выбор как «всё или ничего» вместо того, чтобы сперва вынести слой без платформы
- ✗Полагать, что общий UI — обязательное условие, чтобы разделить view models и бизнес-логику
Уточняющие вопросы
- →Как вы дадите общему модулю доступ к платформенной возможности вроде камеры?
- →Какой сигнал через полгода заставил бы вас пересмотреть это решение?