为什么我的LazyColumn在index变更时无法触发重组?
问题解决方法
问题根源
AndroidView的factory回调仅在组件首次组合时执行1次,后续关联数据变更时不会自动重新执行,你当前把View创建和业务判断逻辑全放在factory中,数据更新后已渲染的View不会自动更新。- LazyList的
itemsIndexed默认使用位置作为key,切换index后如果前后两个列表的长度相近,Compose会认为同位置的item未发生变更,不会触发重组,只有滚动后item被回收再复用才会重新执行逻辑加载新内容。
修复方案
方案1:改动最小的快速修复
给整个LazyColumn绑定index作为key,index变更时直接重建整个列表,适合列表长度较短的场景:
@Composable private fun LazyColumnContent( homepage: List<List<ModuleConfig>>, switcher: HomepageSwitcherTheme?, logo: HomepageThemeNavLogo?, index: Int = 0 ) { LaunchedEffect(key1 = index) { updateHomepageSwitcher(switcher) updateNavigationBarLogo(logo) } // 给LazyColumn加key,index变化时直接重建整个列表 key(index) { LazyColumn( modifier = Modifier .fillMaxSize() .background(vennConfig.themeConfig.backgroundColor?.color) ) { itemsIndexed(homepage[index]) { _, item -> AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> val productsInCategoryCriteriaSatisfied = if (item.requiresProductsInCategoryId.isNullOrEmpty()) true else categoryHasProducts[item.requiresProductsInCategoryId] ?: true return@AndroidView if (productsInCategoryCriteriaSatisfied) moduleFactory.build( item, context ) else View(context) // blank view } ) } } } }
方案2:性能优化版修复
给item加唯一key + 给AndroidView加update回调,避免整个列表重建,适合列表较长的场景:
@Composable private fun LazyColumnContent( homepage: List<List<ModuleConfig>>, switcher: HomepageSwitcherTheme?, logo: HomepageThemeNavLogo?, index: Int = 0 ) { LaunchedEffect(key1 = index) { updateHomepageSwitcher(switcher) updateNavigationBarLogo(logo) } LazyColumn( modifier = Modifier .fillMaxSize() .background(vennConfig.themeConfig.backgroundColor?.color) ) { // 假设ModuleConfig有唯一的id字段作为key,可根据实际业务调整 itemsIndexed(homepage[index], key = { _, item -> item.id }) { _, item -> AndroidView( modifier = Modifier.fillMaxSize(), factory = { context -> // factory仅做View初始化 ModuleViewWrapper(context) }, update = { view -> // update会在item变更时自动执行,负责更新View内容 val productsInCategoryCriteriaSatisfied = if (item.requiresProductsInCategoryId.isNullOrEmpty()) true else categoryHasProducts[item.requiresProductsInCategoryId] ?: true if (productsInCategoryCriteriaSatisfied) { view.bindModuleConfig(item) view.visibility = View.VISIBLE } else { view.visibility = View.GONE } } ) } } }
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

