Относительно недавно я начала использовать Compose. Буду собирать небольшие заметки по мере изучения.
Первое, что мы видим открывая любой проект на Compose — аннотация @Composable. Разберём, что это такое.
@Composable — это специальная аннотация, которая позволяет описывать компоненты UI (пользовательский интерфейс) как функции вместо объектов и автоматически отслеживать изменение состояния. Т.е. раньше у нас были xml, а теперь функции. И все функции, которые должны как-то рисоваться на экране, должны быть с аннотацией.
А ещё, такая функция может быть вызвана только из другой @Composable функции. Также они ничего не возвращают обычно. Там просто описывается UI.
Пример использования:
@Composable
fun Greeting(name: String) {
Text("Hello $name!")
}
Тут мы не сможем вызвать функцию Text("Hello $name!") внутри обычного Kotlin метода, потому что у Text аннотация @Composable.
Вот что происходит под капотом:
- Во время компиляции компилятор вместе с Jetpack Compose превращает каждую @Composable функцию в обычную Kotlin функцию, которая принимает дополнительный параметр — "Composer". Composer — это объект, который управляет отслеживанием состояния и перерисовкой.
- Когда мы вызываем @Composable функцию, Composer записывает этот вызов в специальную структуру данных, называемую "slot table" (я не знаю как это перевести, но вот оно: https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt). В slot table сохраняется весь порядок вызовов и текущее состояние каждого Composable элемента.
- Когда состояние меняется, Composer перебирает slot table и вызывает функции, связанные с измененным состоянием. Это позволяет автоматически обновлять интерфейс при изменении состояния. Звучит очень здорово, потому что не нужно вручную всё делать. Достаточно просто описать состояния.
- Composer использует эффективные алгоритмы для минимального количества перерисовок (так все говорят). Будут перерисованы только те элементы, которые изменились.
Немного рекомендаций:
- Состояние в Compose — это то, что может измениться в любой момент и вызвать перерисовку. Лучше всего вынести состояние на самый верхний уровень, чтобы делить его между несколькими функциями, чтобы не было лишних перерисовок и можно было легко отслеживать и дебажить.
- Используйте LaunchedEffect и другие специальные функции для работы с корутинами, таймерами, подписками и т.п. Эти функции учитывают время жизни Composable функции и отменят корутину, если функция будет уничтожена. Очень сильно поможет с утечками памяти.
- Делайте функции @Composable маленькими. С этой проблемой я столкнулась на практике, что функция становится слишком большой и её сложно читать и там появляется ненужная логика.
- Передавайте состояние с верхнего уровня внутрь @Composable функций, а не меняйте его внутри. Это поможет с тем, чтобы не было лишних перерисовок и чтобы состояние не сбрасывалось (например, при повороте экрана).
- Не вызывайте @Composable функции внутри циклов, условных операторов или лямбда-выражений. Я долго думала про этот совет и почему не стоит вызывать внутри if-else, но всё сводится к чистоте кода и чтобы не перерисовывалось лишний раз.
- Так как @Composable функции могут вызываться в любой момент для перерисовки интерфейса, важно, чтобы они работали быстро. Не забываем про корутины и т.п., что поможет нам избежать блокировки основного потока.
- Используйте remember для сохранения состояния, чтобы избежать повторных перерисовок. Тут, кстати, я знаю, что многие против remember, но я не углублялась пока что в эту тему. На данный момент я его использую.
- Можно использовать @NonRestartableComposable для функций, которые не должны перезапускаться при изменении переданных параметров. Я не использовала на практике, но наверняка есть ситуации, когда пригодится.
- Используйте LazyColumn и LazyRow для больших списков. Это что-то вроде аналога RecyclerView и элементы будут создаваться и уничтожаться по мере прокрутки, вместо создания всех элементов сразу.
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes
P.S. сделано с помощью ChatGPT. :)
Ещё помогла статья: https://lhwdev.github.io/note/compose/how-it-works/