Как избежать сверления винта в Jetpack ComposeAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как избежать сверления винта в Jetpack Compose

Сообщение Anonymous »

Я попытаюсь описать проблему на коротком примере.
Предположим, у нас есть дочерний компонуемый элемент, представляющий пользовательский переключатель, и мы хотим сохранить его неизменяемым, поэтому нам нужно для передачи исходного состояния, а также лямбды для изменения источника истины при переключении переключателя пользователем:

Код: Выделить всё

@Composable
fun CustomSwitch(
title: String? = null,
checked: Boolean = false,
onSwitchChanged: ((Boolean) -> Unit)? = null
){
//...
}
Теперь у нас есть составной родительский объект, представляющий часть экрана, где имеется множество переключателей. Если мы хотим сохранить его неизменяемым, нам нужно раскрыть все свойства дочерних элементов через параметры:

Код: Выделить всё

@Composable
fun PreferencesCard(
switch1Title: String? = null,
switch1Checked: Boolean = false,
OnSwitch1Changed: ((Boolean) -> Unit)? = null,
switch2Title: String? = null,
switch2Checked: Boolean = false,
OnSwitch2Changed: ((Boolean) -> Unit)? = null,
){
CustomSwitch(switch1Title, switch1Checked, OnSwitch1Changed)

CustomSwitch(switch2Title, switch2Checked, OnSwitch2Changed)

//Other composables
}
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: В этом примере составной элемент PreferencesCard действительно глуп, поскольку он ничего не делает, и его можно заменить столбцом или каким-либо " open» компонуемый, включающий только тела функций. Но это только потому, что я хочу сохранить код простым. Предположим, что у него есть другие дочерние элементы и он тоже делает свои собственные действия.
При таком подходе по мере продвижения вверх в иерархии составных элементов нам необходимо сохранить все дочерние параметры, в результате чего списки родительских параметров получаются очень длинными. Эта проблема характерна для декларативных инфраструктур пользовательского интерфейса и, например, в React она известна как Детализация свойств. Он создает сложный и необслуживаемый код, поскольку любое изменение в дочерних элементах (например, добавление нового параметра) приводит к изменениям во всех его родительских элементах. Это противоречит самой концепции инкапсуляции.
Если мы хотим сохранить неизменяемым составной родительский объект, одним из решений является инкапсуляция дочернего состояния и слушателей, чтобы списки параметров были короче:

Код: Выделить всё

data class PreferencesCardState(val switch1Title: String?, val switch1Checked: Boolean, val switch2Title: String?, val switch2Checked: Boolean)

interface PreferencesCardListener {
fun onSwitch1Changed(b: Boolean): Unit
fun onSwitch2Changed(b: Boolean): Unit
}

@Composable
fun PreferencesCard(
state: PreferencesCardState,
listener: PreferencesCardListener
){
CustomSwitch(state.switch1Title, state.switch1Checked, {value -> listener?.onSwitch1Changed(value)})

CustomSwitch(state.switch2Title, state.switch2Checked, {value -> listener?.onSwitch2Changed(value)})

//Other composables
}
С точки зрения состояния это нормально, поскольку Compose достаточно умен, чтобы изменять дочерние элементы только тогда, когда изменяется только дочерний параметр (классы данных с неизменяемыми свойствами стабильны). Но с лямбдами мы можем столкнуться с печально известной проблемой «нестабильных лямбд»: при каждой перекомпозиции PreferencesCard создается новая пара лямбд, что, в свою очередь, приводит к перекомпозиции каждого компонуемого CustomSwitch. (лямбда-выражения рассматриваются Compose как состояние).
Существует трюк, который предотвращает рекомпозицию из-за «нестабильных лямбда-выражений», то есть передача ссылок на методы вместо лямбда-выражений, но эти ссылки (часто указывающие на мутаторы, определенные в ViewModel), все равно необходимо передавать из корневого компонуемого объекта, если только мы не хотим передать всю ViewModel в качестве параметра (что является плохой практикой).
Так как же нам избежать сверления пропеллеров, сохраняя при этом все составные элементы неизменными?


Подробнее здесь: https://stackoverflow.com/questions/733 ... ck-compose
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»