Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Обновлено 25 января 2024
Compose использует специальные composable-функции для построения приложений. С помощью функций вы описываете фигуры и другие данные для создания визуального интерфейса. Функции снабжаются аннотацией @Composable.
Большинство таких функций ничего не возвращают, точнее возвращают Unit(), который можно опустить. В реальности полная запись подобных функций выглядит следующим образом.
@Composable
fun MainScreen(
modifier: Modifier = Modifier
): Unit {
}
У Compose есть три главные фазы, которые следуют друг за другом.

Не менее важная часть - рекомпозиция, т.е. перерисовка UI при изменении входных данных. Умная рекомпозиция — это обновление только тех частей UI, для которых данные изменились.
Compose устроен таким образом, что может пропустить какие-то фазы при обновлении данных, снижая нагрузку, если обновления не затрагивают определённую часть интерфейса. Но по неопытности, можно наоборот усугубить положение, неправильно выстроив логику приложения.
Например, можно улучшить приложение, если обновлять цвет в фазе Draw, минуя другие фазы. Для этой цели подойдёт модификатор drawBehind() вместо модификатора background().
Чуть подробнее про рекомпозицию. Допустим в Column у нас есть два элемента - Text и Icon. Мы решили поменять изображение в значке. Рекомпозиция будет вызвана только у Icon, но Text и Column затронуты не будут.
Это был простейший вариант. Но бывает так, что мы подаём на вход сложный объект. И хотя мы хотим поменять только данные в одном компоненте, рекомпозиция может произойти и в других местах. Такие моменты нужно отслеживать самостоятельно через различные инструменты.
Под капотом компилятор помечает функции как skippable, если можно пропустить рекомпозицию. Казалось бы, для оптимизации нам нужно добиваться, чтобы все функции были skippable. Но на самом деле не от каждой функции надо этого добиваться.
Для каждой skippable-функции генерируется больше кода, чем для non-skippable. Дополнительный код отслеживает её состояние и принимает решение о рекомпозиции, выполняя больше проверок и увеличивя размер приложения. В целом преимущества skippable-функций в виде уменьшения ненужных рекомпозиций перевешивают эти небольшие накладные расходы. Но необязательно добиваться skippable, если ваша функция:
Для всех остальных вариантов мы должны добиваться от функции поведения skippable. Компилятор пометит функцию как skippable, если все её параметры неизменяемы и стабильны.
Стабильными считаются:
Для проверки рекомпозиций можно использовать Layout Inspector.
Изначально Compose использовал Material Design, который сокращённо называют Material 2. В настоящее время рекомендуется использовать Material Design 3 (или Material 3 или M3). При этом API в некоторых случаях сильно изменился и старый код не подходит, приходится переписывать примеры заново.
Настоятельно не рекомендуется смешивать классы из разных пакетов androidx.compose.material и androidx.compose.material3. Возможны ситуации, что в Material 3 ещё нет компонентов, которые были в Material 2, тогда переходить на M3 не стоит. В остальных случаях нужно мигрироовать на новую систему, а новые приложения сразу писать с использованием M3.
Несколько классов из старой Material 2 не изменились с появлением Material 3 и их можно использовать как прежде.
Обратите внимание, что хотя название MaterialTheme осталось прежним, полное имя всё-таки другое - import androidx.compose.material3.MaterialTheme. Это важно, так как названия параметров у них различаются.
Поменялись названия у androidx.compose.material3.Typography.
| M2 | M3 |
|---|---|
| h1 | displayLarge |
| h2 | displayMedium |
| h3 | displaySmall |
| N/A | headlineLarge |
| h4 | headlineMedium |
| h5 | headlineSmall |
| h6 | titleLarge |
| subtitle1 | titleMedium |
| subtitle2 | titleSmall |
| body1 | bodyLarge |
| body2 | bodyMedium |
| caption | bodySmall |
| button | labelLarge |
| N/A | labelMedium |
| overline | labelSmall |
Вместо BackdropScaffold теперь следует использовать Scaffold или BottomSheetScaffold.
Вместо BottomDrawer следует использовать ModalBottomSheet.
Поменялись названия у некоторых компонентов.
androidx.compose.material.BottomNavigation -> androidx.compose.material3.NavigationBar
androidx.compose.material.BottomNavigationItem -> androidx.compose.material3.NavigationBarItem
androidx.compose.material.Chip -> androidx.compose.material3.AssistChip/androidx.compose.material3.SuggestionChip
androidx.compose.material.ModalBottomSheetLayout -> androidx.compose.material3.ModalBottomSheet
androidx.compose.material.ModalDrawer -> androidx.compose.material3.ModalNavigationDrawer.
Но у большинства компонентов изменилось только полное название пакетов, например, было androidx.compose.material.Button, стало androidx.compose.material3.Button.
Scaffold сильно переработали. Вместо параметра backgroundColor теперь используется containerColor. Также убрали ScaffoldState, который использовали для параметра drawerState, так как этот параметр больше не нужен. Для показа Snackbar используется теперь SnackbarHostState. Все drawerXX-параметры удалены, для выдвижной панели используйте ModalNavigationDrawer.
Немного изменился TopAppBar, вдобавок появились родственники - CenterAlignedTopAppBar, MediumTopAppBar, LargeTopAppBar.
Поменялись внешний вид, размеры, цвета у многих компонентов - кнопки, переключатели и т.п.