Jetpack Compose 相同参数创建的Modifier为何会触发不必要重组?
问题解答
关于Modifier的Stable特性疑问
Modifier接口虽然被标记为@Stable,但Stable标记仅代表该类型的等值性变化可被Compose编译器追踪,不代表逻辑相同的不同Modifier实例会被判定为相等。
你在重组时为未选中标签重新构建的Modifier,虽然逻辑参数完全一致,但绝大多数Modifier元素(比如clip、shadow、border等)没有重写equals方法,因此新生成的Modifier实例和旧实例的equals比对返回false,Compose会认为Test的入参发生了变化,触发不必要的重组。
你把Modifier移入Test内部时,Test的入参变为了title:Int、tab、selectedTab这类默认Stable/Immutable的类型,只要这些入参没有变化,Compose就会跳过Test的重组,Modifier的构建逻辑仅在Test真正需要重组时才会执行,因此符合你的预期。
无需移入Modifier的解决方案
你可以通过remember缓存每个标签的Modifier实例,仅当依赖的状态发生变化时才重新计算Modifier,就可以避免不必要的重组:
tabs.forEach { tab -> Log.d("MyTab", "${tab.title}-${tab == selectedTab}") // 仅当tab或selectedTab变化时,才重新计算当前tab的Modifier val tabModifier = remember(tab, selectedTab) { Modifier .clip(RoundedCornerShape(8.dp)) .padding(horizontal = 8.dp) .shadow(0.5.dp, RoundedCornerShape(8.dp)) .background(MaterialTheme.colors.surface) .border(1.dp, if (tab==selectedTab) MaterialTheme.appColors.bottomTabSelect else Color.Transparent, RoundedCornerShape(8.dp)) .clickable { if (tab==selectedTab) { // already selected return@clickable } onTabSelected(tab) } .padding(8.dp) } Test(tab.title, tabModifier) }
这种实现下,只有选中状态发生变化的两个标签(旧选中、新选中)的remember依赖项selectedTab会触发Modifier重新计算,其余标签的Modifier实例保持不变,Test的入参没有变化,就会被Compose跳过重组,完全符合你的性能需求。
内容的提问来源于stack exchange,提问作者Jemshit
相关产品推荐
相关产品推荐

