Android中Volley+JsonObjectRequest回调传数据至Activity失败求助
解决Volley异步请求回调无法传递数据到Activity的问题
我来帮你排查下这个回调失效的问题,看了你的代码,主要有几个关键细节没处理好,导致Activity接收不到请求回来的数据,咱们一步步理顺:
问题根源分析
- 异步请求的时序问题:Volley的网络请求是异步执行的,你调用
getMarketSummary后立刻执行adapter.notifyDataSetChanged(),这时候请求还在后台跑,数据根本没回来;而且你试图通过return listCoins获取结果也是无效的——因为return的时候请求还没完成,listCoins还是空的。 - 回调被多次触发:你在每个请求的
onResponse里都调用callback.onSuccess(listCoins),但这时候listCoins还在被多个请求填充,会导致Activity多次接收不完整的数据,后续请求还会覆盖之前的状态。 - Coin对象复用导致数据混乱:循环里你把
this.coin = coinAux,然后在异步回调里修改这个对象——因为Volley请求是并发的,循环里的coinAux会被快速覆盖,最终所有请求都会修改同一个Coin实例,数据完全乱掉。
修正后的代码实现
第一步:修改请求类的getMarketSummary方法
把返回值改成void(异步请求靠回调传结果,return毫无意义),添加请求计数器确保所有请求完成后再回调,同时每个请求使用独立的Coin对象:
public void getMarketSummary(final DashboardActivity.CoinCallback callback, ArrayList<Coin> listAux, Context context) { Log.d("chegamos a entrar en getCOinData??", "Entramos en getMarketSummary"); listCoins.clear(); requestQueue = Volley.newRequestQueue(context); // 统计需要执行的总请求数 final int totalRequests = listAux.size(); int completedRequests = 0; for (Coin coinAux : listAux) { if (!coinAux.getShortName().equals("BTC")) { // 复制原Coin对象,避免并发修改同一个实例 Coin coin = new Coin(); // 这里手动复制coinAux的所有属性到新对象(根据你的Coin类实际属性调整) coin.setShortName(coinAux.getShortName()); coin.setName(coinAux.getName()); // 其他需要保留的属性都复制过来... String urlMarket = "https://bittrex.com/api/v1.1/public/getmarketsummary?market=btc-SHORTNAME"; String coinShortName = coin.getShortName(); urlMarket = urlMarket.replaceAll("SHORTNAME", coinShortName.toLowerCase()); JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, urlMarket, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { JSONArray result = response.getJSONArray("result"); if (result.length() > 0) { JSONObject data = result.getJSONObject(0); coin.setHigh(Double.parseDouble(data.getString("High"))); coin.setLow(Double.parseDouble(data.getString("Low"))); coin.setLast(Double.parseDouble(data.getString("Last"))); coin.setVolInBtc(Double.parseDouble(data.getString("BaseVolume"))); coin.setBid(Double.parseDouble(data.getString("Bid"))); coin.setAsk(Double.parseDouble(data.getString("Ask"))); coin.setPrevDay(data.getString("PrevDay")); listCoins.add(coin); } } catch (Exception e) { e.printStackTrace(); } finally { completedRequests++; // 所有请求完成后统一回调Activity if (completedRequests == totalRequests) { callback.onSuccess(listCoins); } } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.printStackTrace(); completedRequests++; // 即使请求失败,也要计数,确保最终能回调 if (completedRequests == totalRequests) { callback.onSuccess(listCoins); } } }); requestQueue.add(request); } else { // BTC直接加入列表,计数加1 listCoins.add(coinAux); completedRequests++; if (completedRequests == totalRequests) { callback.onSuccess(listCoins); } } } }
第二步:修正Activity的回调逻辑
Volley的回调是在子线程执行的,必须切换到主线程更新UI,同时把adapter.notifyDataSetChanged()移到回调里(这时候数据才准备好):
public void initCallback() { this.coinCallback = new CoinCallback() { @Override public void onSuccess(ArrayList<Coin> coinListFromRequest) { // 切换到主线程更新UI runOnUiThread(new Runnable() { @Override public void run() { coinList = coinListFromRequest; adapter.notifyDataSetChanged(); // 这里才是更新UI的正确时机 } }); } }; }
第三步:修改请求调用方式
不再接收返回值,因为异步请求的结果只能通过回调获取:
// 只需要发起请求,结果靠回调处理 bittrexAPIRequest.getMarketSummary(coinCallback, coinList, this); // 不要在这里调用notifyDataSetChanged,数据还没回来!
关键说明
- 计数器的作用:确保所有请求(包括成功和失败的)都处理完毕后,再把完整的listCoins传递给Activity,避免多次回调导致数据不完整。
- 独立Coin对象:每个请求使用新的Coin实例,避免并发请求修改同一个对象导致数据混乱。
- 主线程更新UI:Android不允许在子线程更新UI,所以必须用
runOnUiThread包裹UI操作。
内容的提问来源于stack exchange,提问作者Probas Probas
相关产品推荐
相关产品推荐

