Volatile变量在onResponse方法中未更新,Activity无法读取请求状态
解决Volley异步请求后状态无法同步到Activity的问题
刚接触Java和Android的话,遇到这种异步请求的状态同步问题太正常啦!咱们先搞清楚你原来的代码为什么不行,再给你一个简单易懂的解决方案。
问题根源:异步请求的时机问题
你在Activity里调用sendData.sendData()之后,马上就去判断sendData.isSend()——但Volley的网络请求是异步执行的,也就是说sendData()方法会立即返回,而实际的网络请求和响应处理是在后台线程完成的。这时候你判断isSend()的时候,请求还没完成,自然拿不到更新后的状态值。
哪怕你用了volatile修饰变量,也解决不了核心问题:变量还没被修改呢,可见性再好也没用~
解决方案:用回调接口处理异步结果
在Android里,处理异步操作最常用的方式就是回调接口——简单来说,就是让SendData类在请求完成的时候,主动通知Activity“我做完啦,结果是xxx”。
步骤1:定义回调接口
先写一个接口,用来规定请求成功和失败时的通知方法:
public interface OnRequestCompleteListener { // 请求成功时调用,传入解析后的数据 void onSuccess(String parsedData); // 请求失败时调用 void onFailure(); }
步骤2:修改SendData类,添加回调支持
给SendData类加一个回调成员变量,并且在请求完成时触发回调:
public class SendData { // 新增回调成员 private OnRequestCompleteListener mListener; // 你的其他成员变量(queue、url、dataMap等)保持不变 // 新增设置回调的方法 public void setOnRequestCompleteListener(OnRequestCompleteListener listener) { this.mListener = listener; } public void sendData() { StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { String parsedData = parseHTML(response); // 请求成功,通知Activity if (mListener != null) { mListener.onSuccess(parsedData); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // 请求失败,通知Activity if (mListener != null) { mListener.onFailure(); } } }) { // 你的getParams方法保持不变 @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> params = new HashMap<String, String>(); Iterator it = dataMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry pair = (Map.Entry) it.next(); params.put(pair.getKey().toString(), pair.getValue().toString()); it.remove(); } return params; } }; queue.add(stringRequest); } // 原来的setSend、setRetrievedData等方法如果不需要可以删掉,因为回调已经能传递状态和数据了 }
步骤3:在Activity中设置回调,处理结果
现在在Activity的posalji方法里,给SendData设置回调,在回调里处理请求成功或失败的逻辑:
private void posalji(String name, String jmb){ SendData sendData = new SendData(getApplicationContext(), Constants.FIRSTtimeREQUEST_URL); HashMap<String, String> mapa = new HashMap<>(); mapa.put("name", name); mapa.put("jmb", jmb); mapa.put("phone", pNumber); mapa.put("mac_address", getMacAddress()); sendData.setDataMap(mapa); // 设置请求完成后的回调 sendData.setOnRequestCompleteListener(new OnRequestCompleteListener() { @Override public void onSuccess(String parsedData) { // 这里是请求成功后的逻辑,比如更新UI、保存全局变量 // 比如你原来写的"do something"就放在这里 // 注意:Volley的响应回调是在主线程执行的,所以可以直接更新UI哦 } @Override public void onFailure() { // 这里是请求失败后的逻辑 } }); // 发送请求 sendData.sendData(); // 这里不要再判断sendData.isSend()啦,因为请求还没完成 }
额外说明
- 如果需要把返回的数据存入全局变量,直接在
onSuccess方法里赋值就可以了,因为这个方法是在请求完成后才会执行的,能拿到最新的解析后的数据。 - Volley的响应回调默认是在主线程执行的,所以你可以直接在
onSuccess或onFailure里更新UI(比如修改TextView的文字、显示Toast等),不用额外切换线程,非常方便~
内容的提问来源于stack exchange,提问作者fd_4999
相关产品推荐
相关产品推荐

