liujingxing / rxhttp

🔥🔥🔥 Based on OkHttp encapsulation, support Kotlin Coroutines、RxJava2、RxJava3; 30s to get started.
https://juejin.im/post/5ded221a518825125d14a1d4
Apache License 2.0
3.74k stars 457 forks source link

rxLifeScope 及 Async 方法共同使用,调用async方法将导致请求结束回调不被调用 #474

Closed Jason-Lee-1001 closed 3 months ago

Jason-Lee-1001 commented 9 months ago

最近项目需要,要将项目的依赖更新一波,其中rxhttp从2.2.x版本更新到2.9.5,其中rxLife中最显著的变化有这几点

为啥被废弃? 1、同一个FragmentActivity/Fragment下,rxLifeScope与lifecycleScope不能共用;同一个ViewModel下,rxLifeScope与viewModelScope不能共用 2、配合RxHttp发请求时,每次都要开启一个协程来捕获异常,这对于再次封装的人,非常不友好; 目前RxHttp的awaitResult操作符一样可以捕获异常,所以rxLifeScope就没了用武之地,是时候退出历史舞台了 3、不能同lifecycleScope或viewModelScope一样,开启协程时,传入CoroutineContext或CoroutineStart参数 亦没有一系列launchXxx方法 4、rxLifeScope配合RxHttp v2.6.6及以上版本发请求时,调用async方法将导致请求结束回调不被调用

其中第4点就影响到原本的项目代码,如下,其中execute是新扩展增加全局业务异常的捕获,其实就是launch方法的二次封装,在2.2.x的版本还正常使用,更新后确实因为几个方法都是用了async的方法,导致没有返回。也将 rxLifeScope 换为 lifecycleScope 试过,问题依旧。

想知道这个具体原因的本质是什么引起的,要继续使用项目当下的这种代码形式又需要做什么改变?望指教

fun refreshContent() {
        rxLifeScope.execute({
            //先读取缓存数据用于展示
            getWarningCardInfo(true)
            getDataModuleList(homeModuleAdapter, true)
            //真实请求获取最新数据
            getWarningCardInfo()
            getDataModuleList(homeModuleAdapter)
            getTarget(sportStatus)
            getArticle()
            homeEditModule.isGone = homeModuleAdapter.collection.isNullOrEmpty()
            delay(2000)
        }, {}, onFinally = { homeRefreshLayout.finishRefresh() })
 }

其中一个方法👇

suspend fun getDataModuleList(adapter: HomeDataModuleAdapter, fetchCache: Boolean = false) = coroutineScope {
    val user = UserConfigMMKV.user ?: return@coroutineScope
    val familyUserId = UserConfigMMKV.selectedFamilyId ?: return@coroutineScope
    val params = hashMapOf<String, Any?>()
    params["fetchHealth"] = true
    params["visible"] = 1
    params["mainUserId"] = user.uid
    params["familyUserId"] = familyUserId
    val list = if (fetchCache) getCacheOnly(Api.Home.HOME_MODULE_LIST, params).toResultArray<CardModule>().tryAwait()
    else getListAsync<CardModule>(Api.Home.HOME_MODULE_LIST, params, enableCache = true).tryAwait()
    adapter.setData(list)
}

getListAsync👇

suspend inline fun <reified T : Any> CoroutineScope.getListAsync(
    method: String,
    params: HashMap<String, Any?>,
    enableEncrypt: Boolean = true,
    enableCache: Boolean = false,
    cacheMode: CacheMode = CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE
): Deferred<MutableList<T>> = getRequest(method, params, enableEncrypt, enableCache, cacheMode).toResultArray<T>().async(this)
fun RxLifeScope.execute(
    block: suspend CoroutineScope.() -> Unit,
    onError: ((Throwable) -> Unit)? = null,
    onStart: (() -> Unit)? = null,
    onFinally: (() -> Unit)? = null
): Job = launch(block, { e ->
    if (e is SessionExpiredException) {
        RxHttpPlugins.cancelAll()
        CommonApp.obtain<CommonApp>().onAuthExpired()
        return@launch
    } else {
        onError.isNotNull({
            it.invoke(e)
        }, {
            if (e.errorMsg.isEmpty()) ToastKit.show("CODE:${e.errorCode}") else ToastKit.show(e.errorMsg)
        })
    }
}, onStart, onFinally)
liujingxing commented 9 months ago

麻烦提供个简单的案例,并简单说明下问题吧