简体   繁体   English

避免在 Jetpack Compose 的嵌套列中进行重组

[英]Avoid Recomposition in nested column in jetpack compose

I am working on nested column in jetpack compose.我正在研究 Jetpack Compose 中的嵌套列。 I have one list which is huge amount of data coming from server.我有一个列表,其中包含来自服务器的大量数据。 I was checked in Layout Inspector and I see that whenever my item is added in list it recompose and increase counts.我在布局检查器中进行了检查,我发现每当我的项目添加到列表中时,它都会重新组合并增加计数。 So my doubt is if I add 100 item in list one by one, so my Nested Column will be 100 times recompose ?所以我的疑问是,如果我在列表中逐一添加 100 个项目,那么我的Nested Column100 times recompose If not can someone help me on this please?如果没有,有人可以帮我吗?

ListViewComposableActivity.kt ListViewComposableActivity.kt

class ListViewComposableActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppBarScaffold(
                displayHomeAsUpEnabled = true,
                titleId = R.string.activity
            ) {
                ListViewItemStateful()
            }
        }
    }
}

ListViewItemStateful ListViewItemStateful

@Composable
fun ListViewItemStateful(
    viewModel: ListViewModel = koinViewModel(),
) {
    ItemViewListStateless(
        uiState = viewModel.uiState,
        isEnable = viewModel.isEnable,
        scanDeviceList = viewModel.scanResultList,
    )
}

ItemViewListStateless ItemViewList无状态

@Composable
fun ItemViewListStateless(
    uiState: State,
    isEnable: Boolean,
    scanDeviceList: SnapshotStateList<ScanResults>,
) {
    when (uiState) {
        INITIAL,
        FIRST -> {
            ListContent(isEnable, scanDeviceList)
        }
    }
}

ListContent列表内容

@Composable
fun ListContent(isEnable: Boolean, scanDeviceList: SnapshotStateList<ScanResults>) {
    AnimatedVisibility(true) {
        Column(
            modifier = Modifier
                .padding(16.dp)
                .fillMaxSize()
                .verticalScroll(rememberScrollState()),
        ) {
            if (isEnable) {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    DeviceList(
                        scanDeviceList,
                        modifier = Modifier.align(Alignment.Start),
                    )
                }
            }
        }
    }
}

DeviceList设备列表

@Composable
fun ColumnScope.DeviceList(
    scanDeviceList: SnapshotStateList<ScanResults>,
    modifier: Modifier = Modifier,
) {
    Spacer(modifier = Modifier.height(32.dp))
    AnimatedVisibility(
        scanDeviceList.isNotEmpty(),
        modifier = modifier
    ) {
        Column {
            Text(text = "Device List")
            scanDeviceList.forEachIndexed { index, scanResults ->
                Text(text = scanResults.device.name)
            }
        }
    }
}

ListViewModel.kt ListViewModel.kt

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.viewModelScope
import com.abc.app.common.BaseViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class ListViewModel : BaseViewModel() {

    val scanResultList by lazy { mutableStateListOf<ScanResults>() }
    var isEnable by mutableStateOf(false)
        private set
    var uiState by mutableStateOf<State>(State.INITIAL)
        private set

    init {
        viewModelScope.launch {
            (0..10).forEach {
                delay(2000)
                scanResultList.add(ScanResults(Device("item $it")))
            }
        }
        isEnable = true
        uiState = State.FIRST
    }
}


data class ScanResults(val device: Device)
data class Device(val name: String)
enum class State {
    INITIAL,
    FIRST
}

I am adding few items in list to show in layout inspector我在列表中添加了一些项目以在布局检查器中显示

在此处输入图像描述

In above image you can see the DeviceList is recompose 10 times.在上图中,您可以看到DeviceList重组了 10 次。

I checked in Jetpack Compose: Debugging recomposition around 6:40 min he tried to solve recompose issue and there skipped recomposition count is clear.我检查了Jetpack Compose:在 6 分 40 分钟左右调试重组,他试图解决重组问题,并且跳过的重组计数很清楚。 So why it's showing count in my component tree in recomposition and skipped section?那么为什么它在我的组件树中的重组和跳过部分中显示计数? Many thanks非常感谢

In your question when you add a new item to SnapshotStateList whole Column is composed because Column doesn't create a composition scope due to inline keyword.在您的问题中,当您将新项目添加到 SnapshotStateList 时,整个 Column 是组成的,因为 Column 不会由于 inline 关键字而创建组成 scope。 If you create a scope that scope is recomposed when the value it reads changes.如果您创建一个 scope,当它读取的值发生变化时,scope 会重新组合。 You can refer this question and answer as well.您也可以参考这个问题和答案。

Jetpack Compose Smart Recomposition Jetpack Compose 智能重组

Add an item where Text reads device添加一个文本读取设备的项目

@Composable
private fun Item(device: Device) {
    Text(
        modifier = Modifier.border(2.dp, getRandomColor()),
        text = device.name
    )
}

Random color is something i use for displaying recomposition visually随机颜色是我用来在视觉上显示重组的东西

fun getRandomColor() =  Color(
    red = Random.nextInt(256),
    green = Random.nextInt(256),
    blue = Random.nextInt(256),
    alpha = 255
)

Your current setup您当前的设置

在此处输入图像描述

With Item Composable that creates scope.使用创建 scope 的可组合项目。

@Composable
fun ColumnScope.DeviceList(
    scanDeviceList: SnapshotStateList<ScanResults>,
    modifier: Modifier = Modifier,
) {
    Spacer(modifier = Modifier.height(32.dp))
    AnimatedVisibility(
        scanDeviceList.isNotEmpty(),
        modifier = modifier
    ) {
        Column {
            Text(text = "Device List", color = getRandomColor())
            scanDeviceList.forEachIndexed { index, scanResults ->
//                Text(
//                    modifier = Modifier.border(2.dp, getRandomColor()),
//                    text = scanResults.device.name
//                )

                Item(scanResults.device)
            }
        }
    }
}

在此处输入图像描述

And when you have many items, especially they don't fit viewport you can use LazyColumn instead of Column with verticalScroll to limit recomposition amount to number of items that are visible on viewport or visible area of LazyColumn当您有很多项目时,尤其是它们不适合视口时,您可以使用 LazyColumn 而不是 Column with verticalScroll 来将重组量限制为视口上可见的项目数或 LazyColumn 的可见区域

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM