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

Android Kotlin:View与ViewModel间用Flow实现可重试API请求的选型建议

用Flow实现View与ViewModel间的API请求重试方案

场景说明

基于整洁MVVM架构(Activity/Fragment → ViewModel → Repo → DataSource → Retrofit),项目全层使用Flow,需求是:

  • 从View触发API请求
  • 请求失败后,用户点击重试按钮可重新发起请求
  • View与ViewModel间禁止使用LiveData/MutableLiveData,仅用Flow实现

现有代码问题

你当前的ViewModel代码每次调用fetchUserReviewData()都会创建新的Flow实例,View需要重新收集,且无法保留最新状态,重试时需要重新绑定,体验不佳。

推荐方案:使用MutableStateFlow

原因

  1. 状态持久化:MutableStateFlow始终持有最新的状态值,新订阅的View会立即收到当前最新状态(如加载中、成功、失败),无需等待重新请求。
  2. 重试逻辑简洁:点击重试按钮时,只需再次调用fetchUserReviewData(),更新StateFlow的值即可,无需重新创建Flow实例。
  3. 生命周期友好:配合View的生命周期收集,能自动处理订阅与取消,避免内存泄漏。

修改后的ViewModel代码

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class YourViewModel(private val repository: YourRepository) : ViewModel() {
    // 私有可变StateFlow,用于内部更新状态
    private val _userReviewData = MutableStateFlow<Resource<ReviewResponse>>(Resource.idle())
    // 对外暴露不可变的StateFlow,供View订阅
    val userReviewData: StateFlow<Resource<ReviewResponse>> = _userReviewData.asStateFlow()

    fun fetchUserReviewData() {
        // 先发送加载状态
        _userReviewData.value = Resource.loading(true)
        // 在ViewModel的作用域内执行请求,自动跟随ViewModel生命周期销毁
        viewModelScope.launch {
            repository.getUserReviewData().collect { resource ->
                _userReviewData.value = resource
            }
        }
    }
}

View层订阅代码(Activity/Fragment)

import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

lifecycleScope.launch {
    // 仅在STARTED及以上生命周期状态时收集,确保生命周期安全
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.userReviewData.collect { resource ->
            when (resource) {
                is Resource.Loading -> {
                    // 显示加载进度框
                }
                is Resource.Success -> {
                    // 隐藏加载框,展示返回的数据
                }
                is Resource.Error -> {
                    // 隐藏加载框,显示错误提示和重试按钮
                }
            }
        }
    }
}

为什么不选其他Flow?

  • 普通Flow:冷流,每次收集都会重新执行请求逻辑,且无法保留状态,重试时View需要重新绑定,体验差。
  • SharedFlow/MutableSharedFlow:更适合一次性事件流(如Toast提示、页面导航),不适合需要持久化的状态管理,新订阅者不会收到历史状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:18:35