Jetpack составляет список mutableStateOf, который не вызывает повторную композицию при изменении значения свойства в классе элементов списка.
Я думаю, что здесь мне не хватает основной концепции Jetpack Compose. У меня возникла проблема, когда я пытаюсь изменитьnon-constructor
data class
property
внутри компонуемого, когда этот компонуемый является частью наблюдаемого списка.
Не работает: (sadProperty
не объявлен в конструкторе)
data class IntWrapper(val actualInt: Int = 0) {
var sadProperty: Int = 0
}
@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}
fun onClick(item: IntWrapper) {
val indexOf = state.indexOf(item)
val newState = state.minus(item).toMutableList()
val copy = item.copy()
copy.sadProperty = Random.nextInt()
newState.add(indexOf, copy)
state = newState
}
Column() {
for (item in state) {
Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
}
}
}
Работает: (actualInt
объявляется в конструкторе)
data class IntWrapper(var actualInt: Int = 0) {
var sadProperty: Int = 0
}
@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}
fun onClick(item: IntWrapper) {
val indexOf = state.indexOf(item)
val newState = state.minus(item).toMutableList()
val copy = item.copy()
copy.actualInt = Random.nextInt()
newState.add(indexOf, copy)
state = newState
}
Column() {
for (item in state) {
Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
}
}
}
Может кто-нибудь объяснить, почему это происходит?
2 ответа
Это похоже на вопрос и о том, и оKotlin
класс данных, голый со мной, я постараюсь изо всех сил.
Давайте начнем с классов данных Kotlin.
Согласно оData Class
Компилятор автоматически получает следующие элементы из всех свойств, объявленных в основном конструкторе:
- пара equals()/hashCode()
- toString() вида "Пользователь(имя=Джон, возраст=42)"
- componentN() функции, соответствующие свойствам в порядке их объявления.
- копировать ().
В вашем классе данных есть один Primary Constructor, круглая скобка, следующая за именем класса, и одно свойство, объявленное внутри него.
data class IntWrapper(val actualInt: Int = 0) {
var sadProperty: Int = 0
}
с этим, мы можем сказать, что ваш класс данных имеет
- 1 компонент ()
- toString() формы
IntWrapper(actualInt=?)
- сгенерированный
copy()
функция - сгенерированная пара equals()/hashCode()
и снова основано на документам Котлинадокументах:
Компилятор использует только свойства, определенные внутри основного конструктора, для автоматически созданных функций. Чтобы исключить свойство из сгенерированных реализаций, объявите его внутри тела класса:
The equals
будет использовать/оценивать только свойство, объявленное изIntWrapper's
первичный конструктор (т.е.actualInt : Int
) и исключается из него, потому что находится в части тела класса данных.
Теперь рассмотрим следующее:
val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5
val intWrapper2 = IntWrapper(actualInt = 5)
intWrapper2.sadProperty = 10
Log.e("AreTheyEqual?", "${intWrapper1 == intWrapper2}")
он печатает,
E/AreTheyEqual?: true
посколькуequality
видит, что оба производных свойства имеют одинаковое значение5
, исключается из этого сравнения.
val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5
val intWrapper2 = IntWrapper(actualInt = 10)
intWrapper2.sadProperty = 5
отпечатки,
E/AreTheyEqual?: false
потому что сгенерированный equals проверяет, что сгенерированный компонент (actualInt
) НЕ совпадает с двумя экземплярами.
Теперь собираюсьJetpack Compose
, применяя все, что мы понимаем с классами данных,
Первая соответствует всем требованиям
data class
, он создает новый объект с новым значением, и это то, что нужно для запуска.Второй
test
не сработаетre-composition
,Compose
все еще видит то же самоеIntWrapper
например, потому чтоsadProperty
не является частью сгенерированных компонентов, которые будут использоваться операцией равенства класса данных.
В Compose для успешного выполнения операции рекомпозиции необходимо использовать один из следующих двух методов:
1 - с помощью mutableStateListOf(), однако при обновлении значения элемента в списке выполняется операция перекомпоновки
2- Используя свой собственный метод, который вы опубликовали
Но для второго метода вам нужно сообщить Compose, что factInt изменился, поэтому вам нужно создать новый экземпляр int.
Если вы не хотите этого делать, вам нужно подробнее объяснить свой сценарий, чтобы я мог предоставить более полное руководство.