Kotlin封装Volley请求函数返回Model类型ArrayList的实现方案
问题核心原因
- 原代码中
loadMockData是同步返回函数,CoroutineScope.launch启动的异步请求不会阻塞当前函数执行,网络请求还没返回时,后续的解析逻辑就已经执行了,自然拿不到正确的请求结果。 - 你自行添加的
suspendCoroutine封装本身思路是对的,只是缺少异常处理,且调用方式不对。
改造后的完整代码
class Mock @Inject constructor(private val context: Context) { private val url = Constant.prefix + "get_short_videos.php" // 把Volley请求队列改成成员变量,避免每次请求都创建新实例,提升性能 private val requestQueue = Volley.newRequestQueue(context) private val gson = Gson() private val storiesType = object : TypeToken<ArrayList<StoriesDataModel>>() {}.type // 改成suspend函数,支持协程调用,直接返回解析后的结果 suspend fun loadMockData(): ArrayList<StoriesDataModel>? { return try { // 挂起等待网络请求返回结果 val responseStr = getData() Log.e("Response", responseStr) gson.fromJson<ArrayList<StoriesDataModel>>(responseStr, storiesType) } catch (e: Exception) { e.printStackTrace() Toast.makeText(context, "数据加载失败", Toast.LENGTH_SHORT).show() null } } private suspend fun getData() = suspendCancellableCoroutine<String> { cont -> val postRequest: StringRequest = object : StringRequest( Method.POST, url, Response.Listener { response: String? -> response?.let { cont.resume(it) } ?: cont.resumeWithException(NullPointerException("请求返回空结果")) }, Response.ErrorListener { error: VolleyError -> error.printStackTrace() Toast.makeText(context, "请检查网络连接", Toast.LENGTH_SHORT).show() // 错误情况也需要通知协程结束,避免协程一直挂起 cont.resumeWithException(error) } ) { override fun getParams(): Map<String, String>? { val params: MutableMap<String, String> = HashMap() params["mobile"] = context.getSharedPreferences(Constant.prefs, Context.MODE_PRIVATE).getString("mobile","").toString() params["length"] = "0" return params } } postRequest.retryPolicy = DefaultRetryPolicy( 0, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT ) // 协程取消时同时取消Volley请求,避免内存泄漏 cont.invokeOnCancellation { postRequest.cancel() } requestQueue.add(postRequest) } }
Activity中调用示例
所有需要调用该方法的Activity,直接使用lifecycleScope启动协程调用即可,协程会和Activity生命周期绑定,页面销毁时自动取消请求,不会产生内存泄漏:
// 比如在MainActivity中调用 lifecycleScope.launch { val dataList = mockInstance.loadMockData() dataList?.let { // 拿到结果后更新UI即可 recyclerView.adapter = YourAdapter(it) } }
注意事项
- 如果你需要在非Activity/非ViewModel的场景调用,也可以用自定义协程Scope,但要注意手动管理Scope的生命周期,用完及时取消避免内存泄漏。
- 如果你不想使用协程,也可以把
loadMockData改成带回调参数的函数,请求完成后通过回调返回结果,不过协程的写法更简洁,嵌套层级更少。
内容的提问来源于stack exchange,提问作者Pankaz Kumar
相关产品推荐
相关产品推荐

