Comments 15
улучшило наши метрики: длительность лага по отношению к длительности скролла
Серьезно? У вас такие метрики работы программистов? Дальше читать не смог)
Спасибо, много полезной инфы.
Вот это материал! Спасибо, очень полезно!
Привет! Не понял один момент.
Здесь вы говорите, что MyComposable1 не будет затронута, но при этом здесь есть следующий участок кода:
var counter2: Int by remember { mutableStateOf(0) }
про который вы в следующем абзаце говорите, что
В итоге, MyComposable1 будет изменяться или нет ? Утверждения противоречат друг другу. Спасибо!
Привет, здесь работает принцип отложенного чтения через лямбду.
Для лямбды { counter }
в MyComposable2({ counter })
сгенерируется подобный код (условно, не точно такой):
class Lambda(val counter: MutableState<String>) {
fun invoke(): String {
return counter.value
}
}
И уже состояние прочитается в MyComposable2, так как именно там лямбда вызовется.
В тоже время если передавать состояние так:
@Composable
fun MyComposable1() {
...
MyComposable2(counter)
}
то это превратится в
@Composable
fun MyComposable1() {
...
MyComposable2(counter.value)
}
так как делегат по сути скрывает .value от нас, и чтение произойдёт уже в MyComposable1
Спасибо за ответ. Возник уже другой вопрос. Вы написали, что
{ counter } как я понимаю, non-composable функция ? (В ней же не выполняется никакой composable код)
Но в самой статье вы говорите следующее:
А что в итоге произойдет: создание анонимного класса или оборачивание функции в remember ?
Обе вещи. Такой код внутри composable-функции:
val counter = remember { mutableStateOf(3) }
val onClick = { counter.value }
onClick()
Превратится примерно в такой:
val counter = remember { mutableStateOf(3) }
val onClick = remember(counter) { Lambda(counter) }
onClick()
В конце главы про лямбды есть ссылка на видео, где с 25 минуты объясняется, во что превращается лямда в compose. Также лямбды ещё меняются после работы R8 (подобные лямбды объединяются в один класс), но это не так важно в этом контексте, так как на выходе всё равно будет класс (или объект, если не было захвата внешних переменных)
Каким софтом нарисованы диаграммы в статье?
Стоит ли беспокоиться о частой рекомпозиции Image & Icon? У них Painter нестабилен, и как следствие функция не получает свойства skippable. Есть ли рекомендации на этот счёт?
Обычно это не проблема, так Image/Icon - простые элементы (в плане структуры) и когда до них доходит рекомпозиция, то в большинстве случаев она реально нужна.
Избегать рекомпозицию можно за счёт того, чтобы просто не пускать её близко к ним.
Например, в коде ниже мы просто следим за пропускаемостью MyItem и этого достаточно, чтобы Image лишний раз не затрагивалась.
@Composable
fun MyItem(model: MyModel) {
Column {
Text(model.text)
Image(
painter = painterResource(model.image),
contentDescription = null
)
}
}
В каких-то редких кейсам возможно полезно сделать функцию-обёртку для Image, но у нас такие кейсы не встречались.
Другое дело, если мы сами используем Painter в сложных элементах:
@Composable
fun MyComplexItem(image: Painter) {
// ...
}
В таком случаем цена рекомпозиции из-за нестабильной Painter будет высокая и часто будет происходить, когда не нужно. Это можно исправить либо сделав обёртку для Painter и пометив аннотацией, либо указав Painter стабильным с Compose Compiler 1.5.4+, либо передавать другие данные, чтобы создавать Painter внутри. Об этом написано также в этой статье.
Спасибо!
Тем, кто читает статью, совет - через некоторое время прочитайте еще раз, найдете то, что могли пропустить при первом прочтении )
Compose это просто, говорили они???
Спасибо за статью. Очень познавательно.
Осознанная оптимизация Compose