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

如何在BaseViewModel中为RxJava Single型Retrofit请求封装通用safeCall方法?

Single类型Retrofit请求通用封装实现

1. 前置准备

首先在BaseViewModel中初始化RxJava订阅管理器,避免内存泄漏:

import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers

open class BaseViewModel : ViewModel() {
    // 订阅容器,统一管理所有请求的生命周期
    private val compositeDisposable = CompositeDisposable()

    override fun onCleared() {
        super.onCleared()
        // ViewModel销毁时取消所有未完成的请求
        compositeDisposable.dispose()
    }

    // 全局错误处理,可根据业务需求自定义,比如处理401跳登录、网络异常统一提示等
    private fun handleGlobalError(e: Throwable) {
        e.printStackTrace()
        // 此处添加全局错误逻辑
    }
}

2. 核心safeCall方法封装

将通用的线程切换、订阅管理、状态自动控制逻辑封装到BaseViewModel的safeCall方法中:

/**
 * 通用Single类型请求封装方法
 * @param request Retrofit返回的Single请求实例
 * @param isShowLoading 是否自动控制加载状态,默认开启
 * @param loadingLiveData 加载状态绑定的LiveData,自动赋值true/false
 * @param errorLiveData 错误状态绑定的LiveData,请求失败自动赋值true,成功赋值false
 * @param onSuccess 请求成功回调
 * @param onError 自定义错误回调,不填则走全局错误处理
 * @param subscribeScheduler 订阅线程,默认IO线程
 * @param observeScheduler 观察线程,默认主线程
 */
fun <T> safeCall(
    request: Single<T>,
    isShowLoading: Boolean = true,
    loadingLiveData: MutableLiveData<Boolean>? = null,
    errorLiveData: MutableLiveData<Boolean>? = null,
    onSuccess: (T) -> Unit,
    onError: ((Throwable) -> Unit)? = null,
    subscribeScheduler: Scheduler = Schedulers.io(),
    observeScheduler: Scheduler = AndroidSchedulers.mainThread()
) {
    // 自动更新加载状态
    if (isShowLoading) {
        loadingLiveData?.postValue(true)
    }

    val disposable = request
        .subscribeOn(subscribeScheduler)
        .observeOn(observeScheduler)
        .subscribe(
            { result ->
                // 请求成功逻辑
                loadingLiveData?.postValue(false)
                errorLiveData?.postValue(false)
                onSuccess.invoke(result)
            },
            { e ->
                // 请求失败逻辑
                loadingLiveData?.postValue(false)
                errorLiveData?.postValue(true)
                onError?.invoke(e) ?: handleGlobalError(e)
            }
        )

    // 将当前订阅加入统一管理容器
    compositeDisposable.add(disposable)
}

3. 实际调用示例

在子ViewModel中调用该方法,无需再写重复的模板代码:

// 原来的多行模板代码简化为以下实现
safeCall(
    request = parametreService.kitapTurKaydet(json),
    loadingLiveData = parametreEklemeLoading,
    errorLiveData = parametreEklemeError,
    onSuccess = { response ->
        parametreEklemeResponse.value = response
        customSharedPreferences.removeFromSharedPreferences(PARAM_KITAPTUR_DB_KEY)
    }
)

如果需要自定义错误处理,仅需补充onError参数即可:

safeCall(
    request = parametreService.kitapTurKaydet(json),
    loadingLiveData = parametreEklemeLoading,
    errorLiveData = parametreEklemeError,
    onSuccess = { response ->
        // 成功逻辑
    },
    onError = { e ->
        // 自定义错误处理逻辑
    }
)

4. 可选扩展能力

  • 可以定义通用密封类包装请求结果,适配更多业务场景:
    sealed class RequestResult<out T> {
        data class Success<out T>(val data: T) : RequestResult<T>()
        data class Error(val throwable: Throwable) : RequestResult<Nothing>()
    }
    
  • 可添加重复请求拦截逻辑,防止用户重复操作触发多次相同请求
  • 可扩展添加请求防抖、缓存等通用能力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:54:02