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

使用Fuel发送请求时,ProgressBar为何在inline协程函数后才显示?

问题:ProgressBar总是在网络请求完成后才显示

在平板上使用Fuel发送HTTP请求时,希望在请求相关函数开始执行前显示ProgressBar,但它总是在函数执行完成后才出现。单独测试ProgressBar的显示/隐藏功能完全正常。


ProgressBar初始化代码

protected fun initProgressBar(constraintLayoutID: Int): ProgressBar {
    val originalConstraintLayout = findViewById<ConstraintLayout>(constraintLayoutID)
    progressBar = ProgressBar(this).apply {
        id = getInteger(R.integer.INT_PROGRESS_BAR_ID)
        elevation = 999F
        isIndeterminate = true
        layoutParams = ViewGroup.LayoutParams(300, 300)
        visibility = View.GONE

        originalConstraintLayout.addView(this)
    }

    ConstraintSet().run {
        clone(originalConstraintLayout)

        for(position in listOf(ConstraintSet.TOP, ConstraintSet.START, ConstraintSet.END, ConstraintSet.BOTTOM))
            connect(progressBar!!.id, position, constraintLayoutID, position,0)
        applyTo(originalConstraintLayout)
    }
    return progressBar!!
}

原请求函数(inline函数)

原本期望在发送请求前显示ProgressBar的inline函数:

inline fun <reified T : DefaultResponse> sendRequest(
    routeName: String = "",
    routeArgs: String = ""
): T = runBlocking {
    owner.runOnUiThread {
        owner.showProgressBar() // 应该在这里显示,而不是请求完成后
    }

    val adaptedResponse = ResponseFactory.getInstance(owner).getResponseObjectFor(T::class.java.name, routeName)
    val (request, response, result) = Fuel.get(
        "%s%s?%s%s".format(
            networkManager.getURLConnection(),
            (adaptedResponse as DefaultResponse).getRouteName(),
            routeArgs,
            getIndustrialTrypticArgs()
        )
    ).awaitObjectResponseResult(adaptedResponse)

    val exception =
        FailedRequestException(owner.getString(R.string.STR_EXCEPTION_RM_FAILED_REQUEST)).apply {
            setHTTPMessage(response.responseMessage)
            setStatusCode(response.statusCode)
            setUsedRequest(request.url)
        }

    return@runBlocking result.fold<T>(
        { responseObject ->
            if (response.statusCode != 200)
                throw exception
            return@fold responseObject as T
        },
        { error ->
            throw exception.setOriginalError(error.exception)
        }
    )
}

已尝试的解决方式

  • 使用runOnUiThread调用ProgressBar显示逻辑
  • 将显示逻辑封装在launch开启的不同协程线程中

以上方法均无效,ProgressBar仍在inline函数执行结束后才出现。目前疑问:是因为inline函数的特性导致,还是存在并发线程调度问题?


更新1:改为suspend函数

按照建议将sendRequest改为suspend函数:

suspend inline fun <reified T : DefaultResponse> sendRequest(
    routeName: String = "",
    routeArgs: String = "",
    isBlocking: Boolean = true
): T? {
    val adaptedResponse = ResponseFactory.getInstance(owner).getResponseObjectFor(T::class.java.name, routeName) // 1
    val fuelRequest = Fuel.get( // 2
        "%s%s?%s%s".format(
            networkManager.getURLConnection(),
            (adaptedResponse as DefaultResponse).getRouteName(),
            routeArgs,
            getIndustrialTrypticArgs()
        )
    )
    var fuelResponse: T? = null // 3

    CoroutineScope(Dispatchers.Main).launch {
        owner.showProgressBar() // 4
    }
    try {
        fuelResponse =
            if(isBlocking) {
                val answer = fuelRequest.awaitObjectResponseResult(adaptedResponse) // 5

                treatsResponse(answer) as T // 6
            }
            else {
                fuelRequest.responseObject(adaptedResponse) { httpRequest, httpResponse, httpResult ->
                    try {
                        treatsResponse(httpRequest, httpResponse, httpResult) as T
                    }
                    catch (e: FailedRequestException) {
                        println(e.getOriginalError())
                        println(e.getUsedRequest())
                    }
                    finally {
                        owner.hideProgressBar()
                    }
                }
                null
            }
    }
    catch (e: FailedRequestException) {
        println(e.getOriginalError())
        println(e.getUsedRequest())
    }
    finally {
        owner.hideProgressBar()
    }
    return fuelResponse
}

sendRequest的调用被封装在CoroutineScope(Dispatchers.Main).launch中。情况有所改善:ProgressBar开始在函数内部出现而非调用后,但仍希望它在fuelRequest.awaitObjectResponseResult(adaptedResponse)(第5行)之前显示。awaitObjectResponseResult本身也是suspend函数。


更新2:执行顺序问题

逐行调试发现:当owner.showProgressBar()被封装在CoroutineScope(Dispatchers.Main).launch(第4行)中时,它明显在第5行指令之后执行,实际执行顺序始终是1->2->3->5->4->6。当将Dispatchers.Main作为awaitObjectResponseResult的第二个参数传入时,执行顺序变为1->2->3->5->6->4,该网络请求函数似乎始终拥有执行优先级。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:10:56