当可变列表更改时,视图不会重新组合
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")
}
}
这在您的情况下也不起作用,因为对于 mutableStateListOf
,LaunchedEffect
通过指针比较键,并且由于这仍然是同一个容器,因此 LaunchedEffect
不会重新启动.要通过引用进行比较,传递一个普通列表会更清晰:
CountView(viewModel.counter.toList())
请注意,在 LaunchedEffect
内,您已经在协程范围内,可以 运行 挂起函数。
rememberCoroutineScope
通常在需要从其他副作用启动协程时使用,例如按钮点击。
中关于副作用的移动
我有一个应用程序在视图模型中有一个状态列表。我有在列表中添加数字的功能。当我点击一个按钮时,它会在列表中添加数字。但是更改没有反映在另一个视图中。
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")
}
}
这在您的情况下也不起作用,因为对于 mutableStateListOf
,LaunchedEffect
通过指针比较键,并且由于这仍然是同一个容器,因此 LaunchedEffect
不会重新启动.要通过引用进行比较,传递一个普通列表会更清晰:
CountView(viewModel.counter.toList())
请注意,在 LaunchedEffect
内,您已经在协程范围内,可以 运行 挂起函数。
rememberCoroutineScope
通常在需要从其他副作用启动协程时使用,例如按钮点击。