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

开启强跳过模式后Composable仍重组:Lambda对重组跳过的影响问询

Compose中Lambda对组件重组跳过的影响问题

我已使用Kotlin 2.0.0、2.0.10-RC及1.9.20版本测试,排除了Kotlin编译器异常问题。但目前无法理解Lambda如何影响使用该Lambda的组件的重组跳过能力。我为项目生成了Compose Compiler Metrics,所有组件和类(包括Lambda)均被标记为skippable和stable。

当前可正常跳过重组的代码

@Composable
fun CounterScreen(presenter: CounterPresenter) {
  val state = presenter.present()
  CounterContent(state)
}

@Composable
private fun CounterContent(state: CounterState) {
  // 通过remember保存lambda,确保按钮重组被跳过
  val increment = remember {
    { state.eventSink(CounterEvent.Increment) }
  }

  val decrement = remember {
    { state.eventSink(CounterEvent.Decrement) }
  }

  Scaffold(content = { paddingValues ->
    Box(
      modifier = Modifier.fillMaxSize(),
      contentAlignment = Alignment.Center
    ) {
      Column(
        modifier = Modifier.padding(paddingValues),
        horizontalAlignment = Alignment.CenterHorizontally,
      ) {
        TextButton(onClick = increment) {
          Text("Increment")
        }
        Text("Count: ${state.count}")
        Text(state.message)
        TextButton(onClick = decrement) {
          Text("Decrement")
        }
      }
    }
  })
}

Presenter、State、Event实现代码

sealed interface CounterEvent : Event {
  data object Increment : CounterEvent
  data object Decrement : CounterEvent
}

class CounterPresenter : Presenter<CounterState> {

  @Composable
  override fun present(): CounterState {
    var count by rememberSaveable { mutableIntStateOf(0) }
    val message by remember {
      derivedStateOf {
        when {
          count < 0 -> "Counter is less than 0"
          count > 0 -> "Counter is greater than 0"
          else -> "Counter is 0"
        }
      }
    }

    return CounterState(
      count = count,
      message = message,
      eventSink = { event ->
        when (event) {
          Increment -> count += 1
          Decrement -> count -= 1
        }
      }
    )
  }
}

data class CounterState(
  val count: Int,
  val message: String,
  override val eventSink: (CounterEvent) -> Unit,
) : State<CounterEvent>

测试结果与问题

点击Increment按钮10次后,重组计数显示按钮被正确跳过。理论上开启强跳过模式后,可移除remember调用,直接传递Lambda来避免重组,但实际情况并非如此:移除remember并开启强跳过模式后,按钮会随count变化每次都重组,对应的代码如下:

@Composable
private fun CounterContent(state: CounterState) {
  Scaffold(content = { paddingValues ->
    Box(
      modifier = Modifier.fillMaxSize(),
      contentAlignment = Alignment.Center
    ) {
      Column(
        modifier = Modifier.padding(paddingValues),
        horizontalAlignment = Alignment.CenterHorizontally,
      ) {
        TextButton(onClick = { state.eventSink(CounterEvent.Increment) }) {
          Text("Increment")
        }
        Text("Count: ${state.count}")
        Text(state.message)
        TextButton(onClick = { state.eventSink(CounterEvent.Decrement) }) {
          Text("Decrement")
        }
      }
    }
  })
}

内容的提问来源于stack exchange,提问作者Andre Thiele

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 23:22:12