Реактивный ранец Составьте перекомпозицию LazyColumn с помощью remember()

#android #kotlin #android-jetpack-compose

Вопрос:

Я пробовал сочинять Jetpack и наткнулся на что-то со LazyColumn списком и remember() .

 class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp{
                MyScreen()
            }
        }
    }
}

@Composable
fun MyApp(content: @Composable () -> Unit){
    ComposeTestTheme {
        // A surface container using the 'background' color from the theme
        Surface(color = MaterialTheme.colors.background) {
            content()
        }
    }
}

@Composable
fun MyScreen( names: List<String> = List(1000) {"Poofy #$it"}) {
    NameList( names, Modifier.fillMaxHeight())
}

@Composable
fun NameList( names: List<String>, modifier: Modifier = Modifier ){
    LazyColumn( modifier = modifier ){
        items( items = names ) { name ->
            val counter = remember{ mutableStateOf(0) }

            Row(){
                Text(text = "Hello $name")
                Counter(
                    count = counter.value,
                    updateCount = { newCount -> counter.value = newCount } )
            }
            Divider(color = Color.Black)
        }
    }
}

@Composable
fun Counter(count: Int, updateCount: (Int) -> Unit) {
    Button( onClick = {updateCount(count 1)} ){
        Text("Clicked $count times")
    }
}
 

Это выполняется и создает список из 1000 строк, где в каждой строке написано «Привет, Пуфи #N», за которым следует кнопка с надписью «Нажал N раз».

Все это работает нормально, но если я нажму кнопку, чтобы обновить ее количество, это количество не сохранится при прокрутке за кадром и включении обратно.

LazyColumn «Переработка» перекомпилирует строку и счетчик. В приведенном выше примере счетчик поднят вверх, NameList() но я попробовал его самостоятельно Counter() . Ни то, ни другое не работает.

Как правильно помнить графа? Должен ли я хранить его в массиве в действии или что-то в этом роде?

Ответ №1:

Представления для items повторно используются, и с новым index значением значение remember сбрасывается. Это ожидаемое поведение, и вы не должны ожидать, что это значение сохранится.

Вам не нужно держать его в действии, вам просто нужно убрать его из LazyColumn . Например, вы можете сохранить его в списке изменяемых состояний, как показано здесь:

 val counters = remember { names.map { 0 }.toMutableStateList() }
LazyColumn( modifier = modifier ){
    itemsIndexed(items = names) { i, name ->
        Row(){
            Text(text = "Hello $name")
            Counter(
                count = counters[i],
                updateCount = { newCount -> counters[i] = newCount } )
        }
        Divider(color = Color.Black)
    }
}
 

Или в изменяемой карте состояний:

 val counters = remember { mutableStateMapOf<Int, Int>() }
LazyColumn( modifier = modifier ){
    itemsIndexed(items = names) { i, name ->
        Row(){
            Text(text = "Hello $name")
            Counter(
                count = counters[i] ?: 0,
                updateCount = { newCount -> counters[i] = newCount } )
        }
        Divider(color = Color.Black)
    }
}
 

Обратите внимание, что remember это также будет сброшено при повороте экрана, рассмотрите возможность использования rememberSaveable вместо хранения данных внутри модели представления.

Подробнее о состоянии в Compose читайте в документации