LaunchedEffect 没有延迟时应用程序崩溃

Waf*_*_ck 2 android kotlin android-jetpack android-jetpack-compose

为什么我的应用程序在运行此代码时崩溃:

val scrollState = rememberLazyListState(0)
var isLastItemVisible by remember { mutableStateOf(false) }

LaunchedEffect(scrollState) {
    while (!isLastItemVisible) {
        val lastVisibleItemIndex = scrollState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
        val totalItemsCount = scrollState.layoutInfo.totalItemsCount
        isLastItemVisible = lastVisibleItemIndex != null && lastVisibleItemIndex == totalItemsCount - 1
    }

    onLastItemSeen()
}
Run Code Online (Sandbox Code Playgroud)

当我在循环的最后一行添加任何延迟时,一切都正确。我在 LazyRow 中显示项目。

Thr*_*ian 7

它不会让 ANR 崩溃,因为你处于无限循环中,无法滚动。

您可以使用衍生状态来检查最后一项是否可见

val isLastItemVisible by remember {
    derivedStateOf {
        val lastVisibleItemIndex = scrollState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
        val totalItemsCount = scrollState.layoutInfo.totalItemsCount
        lastVisibleItemIndex != null && lastVisibleItemIndex == totalItemsCount - 1
    }
}

LaunchedEffect(isLastItemVisible){
    if (isLastItemVisible){
        // Send event here
    }
}
Run Code Online (Sandbox Code Playgroud)

或 LaunchedEffect 内的 snapshotFlow 仅发送一次事件

// Sends event only once
LaunchedEffect(scrollState) {
    snapshotFlow {
        scrollState.layoutInfo
    }
        .map {
            val lastVisibleItemIndex = it.visibleItemsInfo.lastOrNull()?.index
            val totalItemsCount = it.totalItemsCount
            lastVisibleItemIndex != null && lastVisibleItemIndex == totalItemsCount - 1
        }
        // If it's a one time event filtering it
        .filter { it }
        .distinctUntilChanged()
        .collect {
            println("New Event sent...")
        }
}
Run Code Online (Sandbox Code Playgroud)

或者每次最后一项可见时发送事件

// Sends event every time last item is seen
LaunchedEffect(scrollState) {
    snapshotFlow {
        scrollState.layoutInfo
    }
        .map {
            val lastVisibleItemIndex = it.visibleItemsInfo.lastOrNull()?.index
            val totalItemsCount = it.totalItemsCount
            lastVisibleItemIndex != null && lastVisibleItemIndex == totalItemsCount - 1
        }
        .distinctUntilChanged()
        .collect {visible->
            println("Scroll visible: $visible")
            if (visible){
                println("New Event sent...")
            }

        }
}
Run Code Online (Sandbox Code Playgroud)

另外,我添加了一个示例,当最后一个项目可见时,可以在底端显示按钮,例如

@Preview
@Composable
private fun ListSample() {
    val scrollState = rememberLazyListState(0)

    val isLastItemVisible by remember {
        derivedStateOf {
            val lastVisibleItemIndex = scrollState.layoutInfo.visibleItemsInfo.lastOrNull()?.index
            val totalItemsCount = scrollState.layoutInfo.totalItemsCount
            lastVisibleItemIndex != null && lastVisibleItemIndex == totalItemsCount - 1
        }
    }

    Box {
        LazyColumn(
            state = scrollState
        ) {
            items(20) {
                Text(
                    text = "Row $it",
                    modifier = Modifier.fillMaxWidth().padding(8.dp),
                    fontSize = 20.sp
                )
            }
        }

        if (isLastItemVisible) {
            FloatingActionButton(
                modifier = Modifier.align(Alignment.BottomEnd).padding(8.dp),
                onClick = {

                },
                content = {
                    Icon(imageVector = Icons.Default.ArrowUpward, contentDescription = null)

                }
            )
        }
    }
}
Run Code Online (Sandbox Code Playgroud)