Android Kotlin:如何在继续执行前等待协程完成?
解决Android协程等待异步任务完成后执行后续代码的问题
首先,你当前代码的核心问题是:deleteTable()和getData(companyName)在协程外部同步执行,此时协程还未完成companyName的获取,companyName仍为初始空字符串,无法满足getData的依赖需求。另外,你的finraGetCfruid作为挂起函数,用Volley回调的实现方式是错误的——Volley请求是异步的,函数会直接返回空的cfruid,根本没等请求完成。
第一步:修正协程执行顺序
把依赖companyName的操作放到协程内部,确保在获取到companyName之后再执行:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.currentStock.observe(viewLifecycleOwner) { stock -> lifecycleScope.launch { // 切换到IO线程执行网络请求 val companyName = withContext(Dispatchers.IO) { getCompanyName(stock) } // 拿到companyName后再执行后续操作 deleteTable() getData(companyName) } } }
这里直接将deleteTable和getData放入launch的协程体内,在withContext获取到companyName后执行,保证了执行顺序,无需额外调用join——协程内部默认是顺序执行的。
第二步:修复挂起函数的异步逻辑
你的finraGetCfruid是suspend函数,但Volley的回调方式没有真正挂起协程,函数会直接返回空值。需要用suspendCancellableCoroutine将Volley的回调转换成挂起函数,让协程等待请求完成:
private suspend fun finraGetCfruid(companyName: String): String = suspendCancellableCoroutine { cont -> val url = "https://www.finra.org/finra-data/fixed-income/corp-and-agency" val queue = Volley.newRequestQueue(requireActivity()) val stringRequest = object : StringRequest(Request.Method.GET, url, { /* 无需处理响应体时留空即可 */ }, { error -> Log.e("Error", error.toString()) cont.resumeWithException(error) // 请求失败时抛出异常 }) { override fun parseNetworkResponse(response: NetworkResponse): Response<String> { val cookies = HttpCookie.parse(response.headers?.get("Set-Cookie")) val indexOfEqualSign = cookies[0].toString().indexOf('=') val cfruid = cookies[0].toString().substring(indexOfEqualSign + 1) datainterface.getMoreData(companyName, cfruid) cont.resume(cfruid) // 请求成功时返回结果 return super.parseNetworkResponse(response) } } queue.add(stringRequest) // 协程取消时同步取消Volley请求,避免内存泄漏 cont.invokeOnCancellation { stringRequest.cancel() } }
用suspendCancellableCoroutine可以将回调式异步操作转为挂起函数,Volley请求完成后通过cont.resume()返回结果,失败则用cont.resumeWithException()抛出异常,同时支持协程取消时同步终止Volley请求,避免资源浪费。
补充说明
- 网络请求必须放在IO线程执行,因此用
withContext(Dispatchers.IO)切换线程;lifecycleScope会自动绑定页面生命周期,避免协程内存泄漏。 - 你之前尝试的
job.join()报错,是因为join()是挂起函数,必须在协程内部调用,不能直接在UI线程的同步代码中使用——这也是不推荐runBlocking的原因,它会阻塞UI线程,影响页面流畅度。
内容的提问来源于stack exchange,提问作者David Frick
相关产品推荐
相关产品推荐

