使用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
相关产品推荐
相关产品推荐

