Spring中GlobalScope launch返回值报错'return' is not allowed here如何解决
问题原因与修复方案
错误产生原因
- 语法层面错误:
GlobalScope.launch块内的非局部返回不合法
Kotlin 中只有 inline 函数的 lambda 才支持非局部返回到外层函数,launch函数的 lambda 参数不是 inline 类型,你在launch块内写return apiCall.callApi(...)尝试把返回值传给外层的example函数,语法层面直接不允许,这就是你看到'return' is not allowed here报错的直接原因。
另外从逻辑层面,launch启动的是异步协程,和外层example函数执行完全并行,example函数不会等待协程执行完毕,就算语法允许也拿不到协程的返回值。 - 隐含逻辑错误:
callApi挂起函数实现不符合协程规范
你当前在suspend函数里使用 Retrofit 的异步回调enqueue,函数执行到return tot_records的时候,回调还没触发,永远会直接返回初始值 0,无法拿到接口返回的真实结果,属于典型的异步回调和挂起函数混用的逻辑错误。
修复方案
首先确认你使用的 Retrofit 版本 >= 2.6.0,该版本开始原生支持 Kotlin 协程 suspend 函数,不需要额外适配,是最优解决方案。
第一步:调整Retrofit接口定义
把原来的 ResponseService 接口中的 getResponse 方法修改为 suspend 函数,不需要返回 Call 类型:
interface ResponseService { // 原来的写法:fun getResponse(): Call<Response> // 修改为 suspend fun getResponse(): Response<Response> }
第二步:重写callApi挂起函数
去掉回调逻辑,直接调用 suspend 方法,天然支持挂起等待结果:
suspend fun callApi(param:String):Int{ val retrofit: Retrofit = Retrofit.Builder() .baseUrl(appProperties.sampleUrl) .addConverterFactory(GsonConverterFactory.create()) .build() val service = retrofit.create<ResponseService>(ResponseService::class.java) return try { val response = service.getResponse() if (response.isSuccessful) { println("OK") println(response.body()) println("Tot records") response.body()?.tot_records ?: 0 } else { println("Request failed with code: ${response.code()}") 0 } } catch (e: Exception) { println("Error") println(e.stackTrace) 0 } }
第三步:调整Controller接口,适配协程
Spring Boot 2.0+ 原生支持 Controller 的 suspend 方法,不需要手动启动 GlobalScope 协程,直接声明为 suspend 函数返回结果即可:
val apiCall = ApiCall() @GetMapping("/example") suspend fun example(@RequestParam paramExample:String):Int{ return apiCall.callApi(paramExample) }
如果你的 Spring 版本不支持 Controller 的 suspend 方法,可以改用 async 协程构建器返回 Deferred<Int> 再调用 await() 拿结果,同时不要使用 GlobalScope,避免内存泄漏风险。
低版本Retrofit兼容方案
如果你使用的 Retrofit 版本低于2.6.0,无法使用原生suspend支持,可以用 suspendCancellableCoroutine 把回调转为挂起函数:
suspend fun callApi(param:String):Int = suspendCancellableCoroutine { cont -> val retrofit: Retrofit = Retrofit.Builder() .baseUrl(appProperties.sampleUrl) .addConverterFactory(GsonConverterFactory.create()) .build() val service = retrofit.create<ResponseService>(ResponseService::class.java) val call = service.getResponse() // 协程取消时同时取消Retrofit请求 cont.invokeOnCancellation { call.cancel() } call.enqueue(object : Callback<Response> { override fun onFailure(call: Call<Response>, throwable: Throwable) { println("Error") println(throwable.stackTrace) cont.resume(0) // 失败返回默认值,也可以抛异常上层处理 } override fun onResponse(call: Call<Response>, response: Response<Response>) { println("OK") println(response.body()) println("Tot records") val result = response.body()?.tot_records ?: 0 cont.resume(result) } }) }
内容的提问来源于stack exchange,提问作者zasaz
相关产品推荐
相关产品推荐

