当可变列表更改时,视图不会重新组合

view doesn't get recomposes when mutable list changes

我有一个应用程序在视图模型中有一个状态列表。我有在列表中添加数字的功能。当我点击一个按钮时,它会在列表中添加数字。但是更改没有反映在另一个视图中。

MainActivity.kt

class MainActivity : ComponentActivity() {

    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {

                    Column {
                        Button(onClick = {viewModel.increaseCounter()}) {
                            Text("Increase counter")
                        }
                        CountView(viewModel.counter)
                    }
                }
            }
        }
    }
}

@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun CountView(count: List<Int>) {
    var coroutineScope = rememberCoroutineScope()

    coroutineScope.launch {
        Log.d("inside the coroutine ${count}")
    }
}

MainViewModel.kt

class MainViewModel: ViewModel() {

    var counter = mutableStateListOf<Int>()

    fun increaseCounter() {
        Log.d(">>>", "in viewmodel ${counter.size}")
        counter.add(1)
    }
}

期望的结果: 每当我单击该按钮时,必须打印日志,因为它会在 mutableStateList 中添加一个数字。

但是当我将 mutableStateListOf 更改为 mutableStateOf 并存储一些整数并更改整数时,视图会重新组合并在我单击按钮时打印日志

你的函数没有重组的主要问题是你没有使用视图本身的值,所以 Compose 缓存它。如果您将 Text(count.joinToString { it.to() }) 添加到您的视图,它将起作用。


但首先你不应该直接从可组合函数中使用协程。并且添加 @SuppressLint("CoroutineCreationDuringComposition") 不是错误 IDE 向您显示的正确解决方案:

Calls to launch should happen inside a LaunchedEffect and not composition

所以您的代码应该如下所示:

@Composable
fun CountView(count: List<Int>) {
    LaunchedEffect(count) {
        println("inside the coroutine $count")
    }
}

这在您的情况下也不起作用,因为对于 mutableStateListOfLaunchedEffect 通过指针比较键,并且由于这仍然是同一个容器,因此 LaunchedEffect 不会重新启动.要通过引用进行比较,传递一个普通列表会更清晰:

CountView(viewModel.counter.toList())

请注意,在 LaunchedEffect 内,您已经在协程范围内,可以 运行 挂起函数。

rememberCoroutineScope 通常在需要从其他副作用启动协程时使用,例如按钮点击。

阅读 documentation

中关于副作用的移动