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

ViewModel中处理Supabase API响应及Flow与挂起函数选型

问题解答

一、处理ApiResponse.Loading和ApiResponse.Error状态

假设你的DayState是用于UI展示的状态类(包含加载状态、数据、错误信息等字段),在toDayState函数里可以按以下方式处理不同状态:

1. 处理Loading状态

当接收到ApiResponse.Loading时,核心是告诉UI当前处于加载状态:

  • 将状态中的isLoading设为true
  • 保留现有数据(避免加载过程中UI空白)
  • 清空之前的错误信息(因为是新的请求流程)

示例代码:

fun ApiResponse<Day>.toDayState(currentState: DayState): DayState {
    return when (this) {
        is ApiResponse.Loading -> currentState.copy(
            isLoading = true,
            errorMessage = null
        )
        // 你的Success处理逻辑
        is ApiResponse.Success -> currentState.copy(
            isLoading = false,
            dayData = this.data,
            errorMessage = null
        )
        is ApiResponse.Error -> {
            // 后续处理Error的逻辑
        }
    }
}

2. 处理Error状态

当接收到ApiResponse.Error时,需要传递错误信息并结束加载状态:

  • 将isLoading设为false
  • 提取错误信息(可以用默认提示兜底)
  • 保留现有数据(避免加载失败后UI无内容)

示例代码:

fun ApiResponse<Day>.toDayState(currentState: DayState): DayState {
    return when (this) {
        // Loading和Success处理逻辑
        is ApiResponse.Error -> currentState.copy(
            isLoading = false,
            errorMessage = this.message ?: "加载失败,请稍后重试"
        )
    }
}

在ViewModel中收集Flow时,结合viewModelScope处理状态更新:

viewModelScope.launch {
    supabaseRepository.getDayData()
        .map { it.toDayState(currentDayState.value) }
        .collect { newState ->
            currentDayState.value = newState
        }
}

二、单次API调用:挂起函数还是Flow?

这个选择核心看业务需求和状态管理方式:

1. 优先用挂起函数的场景

如果是纯一次性请求(比如获取单条详情、提交表单、删除数据),且不需要持续监听数据变化,挂起函数更简洁:

  • 代码逻辑直接,不需要处理Flow的收集和生命周期
  • 用try-catch就能直接处理异常,返回单一结果

示例:

// Repository层
suspend fun getDayData(): Day {
    return supabaseClient.from("days").select().single()
}

// ViewModel层
fun fetchDayData() {
    viewModelScope.launch {
        _currentDayState.value = _currentDayState.value.copy(isLoading = true)
        try {
            val data = repository.getDayData()
            _currentDayState.value = _currentDayState.value.copy(
                isLoading = false,
                dayData = data
            )
        } catch (e: Exception) {
            _currentDayState.value = _currentDayState.value.copy(
                isLoading = false,
                errorMessage = e.message ?: "请求失败"
            )
        }
    }
}

2. 优先用Flow的场景

如果满足以下任一情况,Flow(尤其是StateFlow)更合适:

  • 需要持续监听数据变化:比如Supabase的实时订阅,后端数据更新后会主动推送到客户端,必须用Flow接收
  • ViewModel需要统一管理UI状态:把加载、成功、错误状态都包装到一个StateFlow里,UI只需收集这一个流就能处理所有状态,避免分散管理
  • 需要使用Flow操作符:比如对请求结果做转换、合并、防抖等操作,Flow的操作符生态更强大

总结

  • 纯单次无更新的请求:用挂起函数+手动维护UI状态,代码更简单
  • 需要实时更新或统一状态管理:用Flow(StateFlow)包装整个请求生命周期的状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:32:28