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

Kotlin中Observer重复调用问题:点击按钮后触发两次

问题分析与解决方案

问题根源

你的代码中,TextInfo是Composable函数,每次界面重组(比如点击按钮、数据更新)都会重新执行函数内所有代码,这直接导致:

  • 每次重组都会调用viewModel.serverInfoResponse.removeObservers(this)和observe(this),但这里的this是Composable上下文而非Activity上下文,removeObservers无法正确移除旧观察者。
  • 每次重组都会新增一个观察者,LiveData更新时多个观察者被触发,出现多次回调。
  • 手动在Composable里管理LiveData观察者不符合Jetpack Compose状态管理规范,容易引发生命周期问题。

修复代码

修改MainActivity的TextInfo Composable

@Preview
@Composable
fun TextInfo() {
    // 正确获取Activity上下文初始化ViewModel
    val activity = LocalContext.current as ComponentActivity
    val viewModel = ViewModelProvider(activity).get(MainViewModel::class.java)
    
    // 用observeAsState自动将LiveData转为Compose State,自动管理观察者生命周期
    val serverInfo by viewModel.serverInfoResponse.observeAsState()
    
    // 处理空值,默认显示0
    val playerCount = serverInfo?.players ?: 0

    Column() {
        Text(
            text = playerCount.toString(),
        )

        Button(onClick = {
            viewModel.getServerInfo()
        }) {
            Text("Update")
        }
    }
}

优化ViewModel(可选,避免空指针)

给LiveData设置初始值,防止serverInfo为空时出现异常:

// 假设ServerInfo有接收players参数的构造函数,根据实际类结构调整
var serverInfoResponse = MutableLiveData<ServerInfo>(ServerInfo(players = 0))

fun getServerInfo() {
    viewModelScope.launch {
        val apiService = ApiService.getInstance()
        val info = apiService.getInfo()
        serverInfoResponse.value = info
    }
}

关键修改点说明

  • 使用observeAsState:这是Jetpack Compose专为LiveData提供的扩展函数,会自动在Composable进入组合时添加观察者,退出时移除,彻底解决重复添加观察者的问题。
  • 正确获取ViewModel上下文:确保每次重组获取的是同一个ViewModel实例,同时让ViewModelProvider正确关联Activity生命周期。
  • 简化状态管理:直接从转换后的State读取数据,无需手动维护mutableStateOf,代码更简洁且符合Compose状态管理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 14:06:25