我有一个MVI体系结构与活动包含主屏幕
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTheme {
val viewModel: MainScreenViewModel = viewModel(factory = MainScreenViewModel.Factory)
val state by viewModel.viewState.collectAsState()
MainScreen(state, viewModel::handleEvent)
}
}
}
}
主屏幕看起来有点像这样:
@Composable
fun MainScreen(state: MainScreenState, onEvent: (Event) -> Unit) {
TaskList(
tasks = state.items,
onEvent = onEvent,
)
}
@Composable
fun TaskList(tasks: List<TaskState>, onEvent: (Event) -> Unit) {
LazyColumn {
items(items = tasks, key = { it.id }) {
Task(state = it, onEvent = onEvent)
}
}
}
现在,如果ViewModel发出一个新的MainScreenState
,其中一个TaskState
被更改,则TaskList
将重新组合。这是预期的,因为传递了一个新的列表对象。但是不仅改变了的Task
被重组,而且列表中每个Task
可重组。原因不是TaskState
,而是稳定。
导致重组的似乎是onEvent
回调。如果我在MainScreen
中将onEvent = onEvent
更改为onEvent = { onEvent(it) }
,问题就解决了。但我不明白为什么。**方法引用也应该是稳定的吗?**我甚至检查了hashCode,它总是一样的。
1条答案
按热度按时间rdlzhqv91#
即使TaskState稳定,Task组合也会重新组合的原因是因为onEvent回调是通过引用传递的。这意味着当TaskList组合对象被重新组合时,它将获得onEvent回调的新副本。这个新的回调副本不知道TaskState的先前状态,因此它使用新状态调用onEvent函数。
要解决这个问题,可以使用lambda表达式为每个Task组合创建一个新的onEvent回调。这样,每个Task组合都将拥有自己的onEvent回调副本,并且它将知道TaskState的先前状态。
下面是更新后的代码: