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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 14:15:05