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

Jetpack Compose中如何在按钮分支中取消launch返回的Job?

解决方案

你需要将协程Job提升为Composable的状态变量,让它在整个Composable的生命周期内可访问,这样就能在点击事件的不同分支中操作它了。

步骤1:声明状态变量

在你的Composable函数内部、Button上方,用remember和mutableStateOf声明一个可空的Job状态:

val composableScope = rememberCoroutineScope()
var recordingJob by remember { mutableStateOf<Job?>(null) }

注:rememberCoroutineScope()用于创建和Composable生命周期绑定的协程作用域,避免内存泄漏。

步骤2:修改Button点击逻辑

更新点击事件的代码,在启动录制时保存协程Job引用,停止时取消并清空引用:

Button(onClick = {
    if (audioPermissionState.status.isGranted) {
        if (!listener.isListening()) {
            Log.d(TAG, "Audio permission granted")
            // 先取消可能存在的旧任务,防止重复录制
            recordingJob?.cancel()
            listener.listen()
            // 启动新协程并保存Job引用
            recordingJob = composableScope.launch(Dispatchers.Default) {
                listener.read()
                Log.d(TAG, "Listener is reading")
            }
        } else {
            // 取消协程并清空引用
            recordingJob?.cancel()
            recordingJob = null
            listener.stop()
        }
    } else {
        audioPermissionState.launchPermissionRequest()
    }
}) {
    // 优化:根据监听状态切换按钮文本
    Text(
        text = if (listener.isListening()) {
            stringResource(R.string.stop_listening)
        } else {
            stringResource(R.string.start_listening)
        }
    )
}

关键说明

  • 将Job放在Composable状态中,确保它在重组时不会丢失,且能被点击事件的所有分支访问。
  • 启动新录制前取消旧Job,避免多个协程同时读取音频数据。
  • 停止录制后将recordingJob置为null,避免后续操作已失效的Job实例。
  • 额外优化按钮文本,让用户更直观地了解当前操作状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:27:36