Skip to content

网络父类

BaseNetWorkViewModelBaseNetWorkUiStateBaseNetWorkView 构成了“不分页网络请求 + 三态 UI”的标准方案,文件分别位于:

  • app/src/main/java/com/joker/kit/core/base/viewmodel/BaseNetWorkViewModel.kt
  • app/src/main/java/com/joker/kit/core/base/state/BaseNetWorkUiState.kt
  • app/src/main/java/com/joker/kit/core/ui/component/network/BaseNetWorkView.kt

能力概览

  • Flow 即插即用:子类实现 requestApiFlow(),将 Flow<NetworkResponse<T>> 直接交给基类驱动。
  • 统一状态机BaseNetWorkUiState 只保留最常见的 Loading / Success / Error,局部自定义由 UI 决定。
  • 最少样板executeRequest()retryRequest()onRequestStart/Success/Error() 处理协程、错误分发、最小加载时间(240 ms,可用 enableMinLoadingTime 打开)。
  • 导航联动:继承自 BaseViewModel,可直接使用类型安全导航、登录拦截、observeRefreshState() 等能力。
  • 三态视图BaseNetWorkView 负责加载中、失败、成功三套 UI,错误态内置重试按钮,还允许自定义动画或空态组件。

状态模型:BaseNetWorkUiState

BaseNetWorkUiState<T> 是一个 sealed class,用于描述非分页请求:

状态含义默认呈现
Loading进入请求或重试阶段PageLoading()
Success<T>成功拿到数据content Lambda 收到数据并渲染
Error(message, exception)网络/业务失败EmptyNetwork(),带重试按钮

ViewModel 内部通过 MutableStateFlow<BaseNetWorkUiState<T>> 推送状态,视图通过 collectAsState() 即可订阅。

BaseNetWorkViewModel 工作流

  1. 重写请求
    requestApiFlow() 返回真正的网络 Flow,可携带路由参数(借助 SavedStateHandle)。

  2. 触发加载
    通过 executeRequest() 拉取数据,ResultHandler 自动派发 Loading / Success / Error。

  3. 钩子与选项

    • showErrorToast:是否在错误时展示默认 Toast。
    • enableMinLoadingTime:详情页常用,避免闪烁。
    • onRequestStart/Success/Error:默认会把数据写入 _uiState,若页面有额外副作用(记录足迹、曝光等)可在此覆写,但别忘了调用 super 以维持状态更新。
    • getSuccessData():在 UI 处于成功状态时直接读数据。
    • observeRefreshState():监听导航返回的刷新信号。
  4. 重试
    retryRequest() 会复位至 Loading 并重新执行请求,通常绑定到 BaseNetWorkView 的重试按钮。

示例:商品详情

以商品详情为例,ViewModel 负责请求数据并处理足迹、副作用;UI 层遵循模板(context/template/ScreenTemplate.mdViewModelTemplate.md)所倡导的布局结构:Route -> Screen -> Content,并用默认 Scaffold + BaseNetWorkView 演示三态切换。

kotlin
@HiltViewModel
class GoodsDetailViewModel @Inject constructor(
    navigator: AppNavigator,
    userState: UserState,
    savedStateHandle: SavedStateHandle,
    private val repository: GoodsRepository,
) : BaseNetWorkViewModel<GoodsDetail>( // GoodsDetail 是成功态时需要交给 UI 的数据类型
    navigator = navigator,
    userState = userState,
    savedStateHandle = savedStateHandle
) {
    // 从路由获取商品 Id
    private val goodsId: Long = savedStateHandle.toRoute<GoodsRoutes.Detail>().goodsId

    init {
        // ViewModel 初始化时立即发起请求
        executeRequest()
    }

    override fun requestApiFlow(): Flow<NetworkResponse<GoodsDetail>> {
        // 发起详情接口请求
        return repository.getGoodsDetail(goodsId)
    }
}

布局示例:

kotlin
@Composable
fun GoodsDetailRoute(
    viewModel: GoodsDetailViewModel = hiltViewModel(),
) {
    val uiState by viewModel.uiState.collectAsState()

    Scaffold { innerPadding ->
        BaseNetWorkView(
            uiState = uiState,
            padding = innerPadding,
            onRetry = viewModel::retryRequest, // 点击失败页的重试按钮时重新请求
            customLoading = { ShimmerGoodsPlaceholder() }, // 可自定义加载动画;不传则使用默认 PageLoading
        ) { detail -> // detail: GoodsDetail
            GoodsDetailScreen(data = detail)
        }
    }
}
  • BaseNetWorkView 内置加载、失败、成功切换;若需要自定义动画或文案,只需提供 customLoading / customError
  • onRetry 默认触发 retryRequest(),确保状态切回 Loading 并重新请求。
  • GoodsDetailScreen 可以继续拆分 Content 组件,内部遵循 designsystem 中的尺寸/间距常量。

通过这一套基类 + 模板化布局,业务页面只需定义请求 Flow、编写成功态 UI,即可获得一致的加载/失败/重试体验,并与导航、登录拦截、刷新逻辑无缝衔接。

API 参考

BaseNetWorkViewModel<T>

名称类型默认值说明
savedStateHandleSavedStateHandle?null当前路由参数句柄,可读取 URL 参数
uiStateStateFlow<BaseNetWorkUiState<T>>Loading供 UI 层订阅的三态数据
_uiStateMutableStateFlow<BaseNetWorkUiState<T>>Loading子类可覆写以自定义状态
showErrorToastBooleanfalse是否在 Error 阶段弹 Toast,protected open
enableMinLoadingTimeBooleanfalse是否启用 240ms 最短加载动画
requestApiFlow()函数-protected abstract fun requestApiFlow(): Flow<NetworkResponse<T>>
executeRequest()函数-触发请求并派发 Loading/Success/Error
retryRequest()函数-重置状态后重新执行请求
onRequestStart()函数-默认调用 setLoadingState(),可覆写插入逻辑
onRequestSuccess(data)函数-默认写入成功状态,可覆写处理副作用
onRequestError(message, exception)函数-默认调用 setErrorState()
setLoadingState()函数-_uiState 设为 Loading
setSuccessState(data)函数-_uiState 设为 Success(data)
setErrorState(message, exception)函数-_uiState 设为 Error,可自定义提示
getSuccessData()函数-直接读取成功态数据,非成功状态会抛异常
observeRefreshState(backStackEntry, key)函数key = RefreshResultKey监听导航返回刷新信号

BaseNetWorkView

参数类型默认值说明
uiStateBaseNetWorkUiState<T>-控制 Loading/Success/Error 展示
modifierModifierModifier用于 fillMaxSize()background()
paddingPaddingValuesPaddingValues()ScaffoldinnerPadding 透传即可
onRetry() -> Unit{}失败页点击后触发的回调
customLoading@Composable (() -> Unit)?null自定义加载态,null 时用 PageLoading()
customError@Composable (() -> Unit)?null自定义错误态,默认 EmptyNetwork()
content@Composable (data: T) -> Unit-成功态内容,参数为请求结果