Я изо всех сил пытаюсь понять, следует ли мне передать значение составной функции или лямбда. Давайте посмотрим на мой пример. Пожалуйста, пропустите LaunchedEffect
, это просто для моделирования изменяемых данных.
Мои вопросы: в этом случае я должен использовать ComposableTextDirect
или ComposableTextLambda
и почему?
@Composable
fun ComposableContainer() {
val coroutineScope = rememberCoroutineScope()
var aTextThatCanBeChangedBySomethingElse by remember {
mutableStateOf("")
}
LaunchedEffect(key1 = Unit) {
coroutineScope.launch(Dispatchers.IO) {
while (isActive) {
delay(1_000L)
aTextThatCanBeChangedBySomethingElse = Date().toString()
}
}
}
Column {
ComposableTextDirect(text = aTextThatCanBeChangedBySomethingElse)
ComposableTextLambda {
aTextThatCanBeChangedBySomethingElse
}
}
}
@Composable
fun ComposableTextDirect(text: String) {
Text(text = text)
}
@Composable
fun ComposableTextLambda(provider: () -> String) {
Text(text = provider())
}
Я попробовал приведенный выше код, и он работает хорошо и такой же, как и другие.
@ Tenfour04 Мне просто интересно, передать ли значение напрямую или передать значение лямбда, чтобы избежать перекомпоновки.
использование лямбда является одним из предложений по повышению производительности, но в большинстве случаев это избыточно и только усложняет ваш код, поэтому используйте его, если у вас действительно есть проблемы с производительностью из-за частых обновлений - например. с помощью анимации.
Так что, в принципе, как вы это написали, это не будет иметь никакого значения, но обратите внимание на одну вещь. Если вы измените свой код следующим образом:
@Composable
fun ComposableContainer() {
val coroutineScope = rememberCoroutineScope()
var aTextThatCanBeChangedBySomethingElse = remember {
mutableStateOf("")
}
LaunchedEffect(key1 = Unit) {
coroutineScope.launch(Dispatchers.IO) {
while (isActive) {
delay(1_000L)
aTextThatCanBeChangedBySomethingElse.value = Date().toString()
}
}
}
Column {
Text(text = "Test")
// ComposableTextDirect(text = aTextThatCanBeChangedBySomethingElse.value)
ComposableTextLambda {
aTextThatCanBeChangedBySomethingElse.value
}
}
}
Будет разница. Просто посмотрите на инспектор компоновки и рекомпозиции. Текст будет перекомпонован несколько раз, если вы используете
ComposableTextDirect(text = aTextThatCanBeChangedBySomethingElse.value)
и он не будет перекомпонован в случае, если вы используете
ComposableTextLambda {
aTextThatCanBeChangedBySomethingElse.value
}
Причина этого в том, что каждый раз, когда вы наблюдаете изменяемое состояние в каком-либо составном объекте, вы будете перекомпоновывать его при каждом изменении значения.
Короче говоря, используйте изменяемое состояние на самом низком уровне, чтобы избежать рекомпозиций.
Спасибо за ваш очень подробный ответ. То есть вы имеете в виду, что если возможно, я должен использовать ComposableTextLambda
, чтобы уменьшить рекомпозицию? Но я думаю, что это сделает код более сложным. Я думаю, что ComposableTextLambda
все еще получают рекомпозицию, когда текст изменился. Но с лямбдой это уменьшает объем композиции, верно?
Да, в основном в этом случае это было бы сложнее, поэтому вам было бы проще перемещать свои изменяемые данные внутри ComposableTextLambda. Бывают, конечно, времена, когда это будет невозможно, и это тоже нормально, но перекомпоновки будут происходить чаще на верхних уровнях.
Я не могу заметить каких-либо различий в поведении, если не учитывать дополнительный функциональный объект, который генерируется каждый раз, когда вы вызываете лямбда-версию.