Pull to refresh

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 (подобные лямбды объединяются в один класс), но это не так важно в этом контексте, так как на выходе всё равно будет класс (или объект, если не было захвата внешних переменных)

Просто не хотел удлинять и усложнять статью ещё и детальным описанием преобразованием лямбды в котлине

Каким софтом нарисованы диаграммы в статье?

Привет, первая - draw io, вторая и третья взята из ресурсов Jetpack Compose (вторая просто через фотошоп переведена)

Стоит ли беспокоиться о частой рекомпозиции 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 внутри. Об этом написано также в этой статье.

Спасибо!
Тем, кто читает статью, совет - через некоторое время прочитайте еще раз, найдете то, что могли пропустить при первом прочтении )

Спасибо за статью. Очень познавательно.

Sign up to leave a comment.