You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Jetpack Compose中LeftControlContainers组件重复重组?

解决Compose中不必要的重组问题

我有一个仅含单个参数的可组合函数:

@Composable
private fun LeftControlContainers(
    uiControl: EditorUiControl,
) {
    val controls = rememberUpdatedState(uiControl)

    val configState = remember { derivedStateOf { controls.value.controlMap[ArtifaktControls.CONFIGURATION.id] } }

    Column(
        modifier = Modifier.width(144.dp),
        verticalArrangement = Arrangement.spacedBy(Theme.spacingSystem.xxs)
    ) {
        key(configState.value, controls.value) {
            controls.value.Draw(
                uiElement = EditorUiDropDown(),
                elementId = ArtifaktControls.CONFIGURATION.id,
            )
        }
    }
}

EditorUiControl类定义如下:

class EditorUiControl(
    val defaultControlMap: ImmutableMap<String, NewEditorElement>,
    val controlMap: ImmutableMap<String, NewEditorElement>,
    val setControlValue: (
        elementId: String,
        updatedEditorElement: NewEditorElement,
        changedValue: EditorElementValue<*>,
    ) -> Unit,
) {
    @Composable
    fun Draw(
        uiElement: EditorUiElement,
        elementId: String,
        modifier: Modifier = Modifier,
        filtrationMethod: FiltrationMethod = FiltrationMethod.SHUTDOWN,
    ) {
        uiElement.Draw(
            modifier = modifier,
            elementId = elementId,
            defaultControlMap = defaultControlMap,
            controlMap = controlMap,
            setControlValue = setControlValue,
            filtrationMethod = filtrationMethod,
        )
    }
}

目前遇到的问题是:每当任意单个项发生变化时,所有此类可组合函数都会触发重组,每次约200次。尝试过用remember和key包裹,但日志显示仍会每次重组,请问该如何避免?


问题根源分析

  1. EditorUiControl不是稳定类:Compose判断是否重组的核心是参数稳定性,普通类默认以引用相等判断变化。如果父组件每次重组都创建新的EditorUiControl实例(哪怕内部属性一致),Compose都会认为参数更新,触发目标函数重组。
  2. key依赖冗余:原代码中key同时绑定configState.value和controls.value,只要EditorUiControl实例变化,不管目标配置项是否改动,都会触发key块内的重组。
  3. setControlValue可能不稳定:如果传递的是临时lambda,每次父组件重组都会生成新实例,即使逻辑相同,也会被判定为参数变化。

解决方案

1. 标记EditorUiControl为稳定类

给EditorUiControl添加@Stable注解,让Compose通过内容相等而非引用相等判断参数变化:

@Stable
class EditorUiControl(
    val defaultControlMap: ImmutableMap<String, NewEditorElement>,
    val controlMap: ImmutableMap<String, NewEditorElement>,
    val setControlValue: (
        elementId: String,
        updatedEditorElement: NewEditorElement,
        changedValue: EditorElementValue<*>,
    ) -> Unit,
) {
    // 保持原有Draw方法不变
}

注:ImmutableMap本身是稳定类型,只要setControlValue是稳定引用(比如ViewModel的函数),这个类就能满足稳定类要求。

2. 精简key的依赖项

只保留真正影响UI的依赖,移除冗余的controls.value,确保只有目标配置项变化时才触发内部重组:

key(configState.value) {
    print("recomposed")
    controls.value.Draw(
        uiElement = EditorUiDropDown(),
        elementId = ArtifaktControls.CONFIGURATION.id,
    )
}

3. 拆分参数,避免传递整个对象

如果LeftControlContainers只用到EditorUiControl的部分属性,直接传递这些属性而非整个对象,缩小重组触发范围:

@Composable
private fun LeftControlContainers(
    defaultControlMap: ImmutableMap<String, NewEditorElement>,
    controlMap: ImmutableMap<String, NewEditorElement>,
    setControlValue: (String, NewEditorElement, EditorElementValue<*>) -> Unit
) {
    val configElement = remember(controlMap) { 
        controlMap[ArtifaktControls.CONFIGURATION.id] 
    }

    Column(
        modifier = Modifier.width(144.dp),
        verticalArrangement = Arrangement.spacedBy(Theme.spacingSystem.xxs)
    ) {
        key(configElement) {
            EditorUiDropDown().Draw(
                elementId = ArtifaktControls.CONFIGURATION.id,
                defaultControlMap = defaultControlMap,
                controlMap = controlMap,
                setControlValue = setControlValue
            )
        }
    }
}

4. 确保setControlValue稳定

如果setControlValue是父组件传递的lambda,用remember缓存它,避免每次重组生成新实例:

// 父组件中传递时
val stableSetControlValue = remember {
    { elementId: String, element: NewEditorElement, value: EditorElementValue<*> ->
        // 原逻辑
    }
}
LeftControlContainers(uiControl = EditorUiControl(..., setControlValue = stableSetControlValue))

或者直接使用ViewModel中的函数引用(ViewModel是稳定类,其方法引用也稳定)。


内容的提问来源于stack exchange,提问作者Denis Popkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 06:42:19