Android Compose — ошибка «Снимок не открыт» после сборки приложения

avatar
Arseniy
8 августа 2021 в 22:56
668
2
0

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

composableScope.launch {
    listState.animateScrollToItem(
        index = indexToScroll,
        scrollOffset = offsetToScroll
    )
}

Все работает как положено, кроме одного. После первого запуска из студии Android всегда возникает сбой java.lang.IllegalStateException: Snapshot is not open. Если я открываю приложение без сборки или запускаю сборку во второй раз (без изменений кода), все работает хорошо. Я создал суть с примером моего кода

@Composable
fun MyComponent() {
    val composableScope = rememberCoroutineScope()
    val listState = rememberLazyListState()

    LazyColumn(
        state = listState
    ) {
        .....
    }

    val isScrollInProgress by remember {
        derivedStateOf {
            listState.isScrollInProgress
        }
    }

    LaunchedEffect(isScrollInProgress) {
        if(!isScrollInProgress){
            val visiblePlaceHeight = listState.layoutInfo.viewportEndOffset + listState.layoutInfo.viewportStartOffset
            val itemHeight = listState.layoutInfo.visibleItemsInfo.firstOrNull()?.size
            itemHeight?.let {
                val centerPosition = (visiblePlaceHeight - itemHeight) / 2
                val offsetToScroll = itemHeight - centerPosition
                val indexToScroll = when (listState.firstVisibleItemIndex) {
                    listState.layoutInfo.totalItemsCount - 2 -> listState.firstVisibleItemIndex - 1
                    else -> listState.firstVisibleItemIndex
                }
                if (listState.firstVisibleItemScrollOffset != offsetToScroll && offsetToScroll > 0) {
                    composableScope.launch {
                        // listState.animateScrollToItem leads to java.lang.IllegalStateException: Snapshot is not open
                        listState.animateScrollToItem(
                            index = indexToScroll,
                            scrollOffset = offsetToScroll
                        )
                    }
                }
            }
        }
    }
}

Если я удалю код в composableScope.launch {...}, проблема исчезнет.

Источник
Pylyp Dukhov
9 августа 2021 в 03:07
0

пожалуйста, добавьте больше контекста, где этот код называется?

Arseniy
9 августа 2021 в 07:23
0

Я добавил полный пример моего составного метода

Ответы (2)

avatar
korita
20 марта 2022 в 01:06
0

это также произошло в моем приложении для создания сообщений я попытался сделать minifyEnabled ложным, и он снова не вылетал поэтому вы можете установить минимизацию в build.gradle,

minifyEnabled false

или сохранить классы compose в proguard-rules.pro

-keep public class androidx.compose.*.**{*;}
avatar
Pylyp Dukhov
9 августа 2021 в 07:50
0
Блок

LaunchedEffect уже вызывается в области сопрограммы, поэтому нет необходимости обертывать animateScrollToItem другой сопрограммой.

Базовый пример: список будет прокручиваться до элемента 40 после секундной задержки с момента появления представления.

val listState = rememberLazyListState()

LaunchedEffect(Unit) {
    delay(1000)
    listState.animateScrollToItem(40)
}

LazyColumn(
    state = listState
) {
    items(100) {
        Text(text = it.toString())
    }
}
Arseniy
9 августа 2021 в 08:30
0

Я попытался вызвать animateScrollToItem без composableScope.launch, но список не прокручивается. Знаете хороший пример кода для LaunchedEffect и прокрутки?

Pylyp Dukhov
9 августа 2021 в 09:34
1

gist.github.com/PhilipDukhov/951896a1538094082bfe5f2e602f24c4 это прекрасно работает

Pylyp Dukhov
26 сентября 2021 в 10:42
0

Привет, @Arseniy, этот ответ решил твой вопрос? Если да, пожалуйста, примите его, поставив галочку под счетчиком голосов.

Arseniy
27 сентября 2021 в 13:26
0

К сожалению, это не решило мою проблему. Но ваш код помог мне понять некоторые другие детали. Я собираюсь опубликовать полный код моего примера с проблемой.