如何等待Android Volley请求响应 解决异步返回数组为空问题
问题根因
Volley的网络请求默认在异步子线程执行,你当前的写法会在将请求加入队列后立刻返回chartDataList,此时请求还未完成、回调逻辑还未触发,自然拿到的是空数组。Android禁止在主线程阻塞等待网络请求返回,否则会触发ANR异常,因此不能直接用同步阻塞的方式等待结果,推荐用接口回调的方式获取请求完成后的数据。
另外你原有代码存在隐藏bug:仅在循环外创建了一次ChartData实例,循环内反复修改同一个对象的属性,最终列表里所有元素都会是最后一条数据的内容,后续方案中已经修复该问题。
解决方案1:Java接口回调实现(通用方案)
步骤1:自定义回调接口
public interface VolleyResponseCallback { // 请求成功返回填充完成的数组 void onSuccess(List<ChartData> dataList); // 请求/解析失败返回错误信息 void onError(String errorMsg); }
步骤2:修改原有请求方法
去掉方法返回值,改为传入回调参数,处理完逻辑后通过回调返回结果:
public void getVolleyResponse(VolleyResponseCallback callback) { requestQueue = Volley.newRequestQueue(getApplicationContext()); JsonObjectRequest req = new JsonObjectRequest( Request.Method.GET, urlCreator(getCoinName()), null, response -> { try { JSONArray arr = response.getJSONArray("prices"); List<ChartData> chartDataList = new ArrayList<>(); for (int i = 0; i < arr.length(); i++) { JSONArray jsonArray = arr.getJSONArray(i); // 每次循环创建新的ChartData实例,修复对象复用bug ChartData chartData = new ChartData(); chartData.setTimeStamp(timeStampConverter(jsonArray.getString(0))); chartData.setCost(jsonArray.getDouble(1)); chartDataList.add(chartData); } // 回调返回成功结果 callback.onSuccess(chartDataList); } catch (JSONException e) { e.printStackTrace(); callback.onError("数据解析失败:" + e.getMessage()); } }, error -> { String errorTip = "请求失败:" + (error.getMessage() == null ? "未知错误" : error.getMessage()); Toast.makeText(getApplicationContext(), errorTip, Toast.LENGTH_LONG).show(); callback.onError(errorTip); }); requestQueue.add(req); }
步骤3:调用方法获取数据
getVolleyResponse(new VolleyResponseCallback() { @Override public void onSuccess(List<ChartData> dataList) { // 此处拿到填充完成的数组,可直接更新UI或执行后续逻辑 // 回调默认运行在主线程,无需额外切线程 } @Override public void onError(String errorMsg) { // 自定义错误处理逻辑 } });
解决方案2:Kotlin协程实现(Kotlin项目可选)
如果项目使用Kotlin开发,可以通过suspendCoroutine将回调转为挂起函数,写法更简洁:
suspend fun getVolleyResponse(): Result<List<ChartData>> = suspendCoroutine { continuation -> val requestQueue = Volley.newRequestQueue(applicationContext) val req = JsonObjectRequest( Request.Method.GET, urlCreator(getCoinName()), null, { response -> try { val arr = response.getJSONArray("prices") val dataList = mutableListOf<ChartData>() for (i in 0 until arr.length()) { val jsonArray = arr.getJSONArray(i) val chartData = ChartData().apply { timeStamp = timeStampConverter(jsonArray.getString(0)) cost = jsonArray.getDouble(1) } dataList.add(chartData) } continuation.resume(Result.success(dataList)) } catch (e: JSONException) { e.printStackTrace() continuation.resume(Result.failure(e)) } }, { error -> Toast.makeText(applicationContext, "请求失败", Toast.LENGTH_LONG).show() continuation.resume(Result.failure(error)) } ) requestQueue.add(req) }
调用时直接在协程作用域中获取结果即可。
注意事项
- 不要使用
CountDownLatch等工具在主线程阻塞等待异步请求返回,会直接触发ANR异常 - 回调方法默认运行在主线程,可以直接执行UI更新操作
内容的提问来源于stack exchange,提问作者Halil Sahin
相关产品推荐
相关产品推荐

