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

点击按钮发起API调用后,第二次点击ProgressBar进度条不显示

问题原因及解决方案

核心问题分析

你的代码存在两个关键问题,导致二次点击时ProgressBar不显示:

  1. 重复注册LiveData Observer + LiveData粘性特性
    每次点击按钮都会创建新的协程,并在协程内部注册新的ApiResponse Observer。LiveData的粘性特性会让新注册的Observer立刻收到之前缓存的响应结果,导致你刚把ProgressBar设为VISIBLE,就被Observer回调立刻设为INVISIBLE,视觉上看不到ProgressBar。

  2. Observer注册时机错误
    Observer不应该放在协程内部注册,协程是异步执行逻辑,重复注册会导致多个回调实例,进一步加剧状态混乱。

另外你添加delay后能看到ProgressBar,只是因为延迟了Observer的回调时机,给了ProgressBar短暂的显示窗口,并非根本解决办法。

修复步骤

1. 统一注册Observer,只执行一次

在Fragment的onViewCreated或Activity的onCreate中注册Observer,避免重复注册:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    // 仅注册一次Observer,处理所有API响应
    TestVM.ApiResponse.observe(viewLifecycleOwner) { apiResult ->
        // 不管成功失败,先隐藏ProgressBar
        myBinding.TestProgressBar.visibility = View.INVISIBLE
        
        when (apiResult) {
            is TestWrapper.Success -> {
                myBinding.MyTextView.text = String.format(
                    getString(R.string.testString),
                    apiResult.data // 替换为你的实际数据字段
                )
            }
            is TestWrapper.Error -> {
                // 可选:处理错误,比如显示错误提示
            }
        }
    }
}

2. 简化按钮点击逻辑,直接启动协程发起请求

去掉TestJob的自定义getter逻辑,每次点击按钮直接启动新协程,同时确保传入最新的用户输入数据给ViewModel:

myBinding.apiCall.setOnClickListener {
    val userInput = myBinding.editText.text.toString().trim()
    // 先执行数据有效性验证
    if (userInput.isNotEmpty()) { // 替换为你的实际验证规则
        myBinding.TestProgressBar.visibility = View.VISIBLE
        // 启动协程发起API请求
        viewLifecycleOwner.lifecycleScope.launch {
            TestVM.makeApiCall(userInput) // 传入最新输入数据
        }
    }
}

3. 修正ViewModel的API调用逻辑

确保ViewModel每次接收新的输入数据,并更新LiveData:

class TestVM : ViewModel() {
    private val _apiResponse = MutableLiveData<TestWrapper>()
    val ApiResponse: LiveData<TestWrapper> = _apiResponse

    // 接收用户输入数据,发起API请求
    suspend fun makeApiCall(inputData: String) {
        try {
            // 实际API请求逻辑,比如用Retrofit
            val response = yourApiService.fetchData(inputData)
            _apiResponse.postValue(TestWrapper.Success(response))
        } catch (e: Exception) {
            _apiResponse.postValue(TestWrapper.Error(e.message ?: "请求失败"))
        }
    }
}

额外注意事项

  • 避免复用已完成的Job:Job一旦执行完毕就进入Completed状态,无法再次启动,所以每次请求都应该创建新的协程。
  • 数据验证要放在UI线程:确保点击按钮时先在主线程完成数据有效性校验,再发起异步请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:55:05