如何在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
相关产品推荐
相关产品推荐

