需求:高效地向服务器请求数据并解析。
涉及的主要工具类:
HttpManager 大哥类。最重要的类,封装了GET和POST方法。所有的参数都要经过这个类发送给服务器。
HttpRequestListener 监听接口。封装了请求状态和毁掉方法
HttpRequestVo 信使类。封装了http请求的参数。
JSONParser 解析器。
HttpRequestVo 封装了Http请求中携带的参数。这个类类似于一个通信使者,在主调用函数中赋值,传递给HttpManager,让后者将它进一步加工成http请求。
public class HttpRequestVo {
//请求地址
public String requestUrl;
//上下文
public Context context;
//客户端的本地请求参数
public HashMap<String, String> requestDataMap;
//JSON请求参数
public JSONObject requestJson;
//JSON解析器
public JSONParser parser;
}
HttpRequestListener是一个接口,它里面封装了几个Request的返回状态,还有一个很重要的回调方法action,用于返回网络请求的结果状态,以及解析好的数据Object(一般为HashMap)。
public interface HttpRequestListener {
public static final int BASE_EVENT = 0x100;
//没有网络提示
public static final int EVENT_NO_NETWORK = BASE_EVENT + 1;
//网络异常
public static final int EVENT_NETWORK_ERROR = BASE_EVENT + 2;
//获取网络数据失败
public static final int EVENT_GET_DATA_ERROR = BASE_EVENT + 3;
//获取网络数据成功
public static final int EVENT_GET_DATA_SUCCESS = BASE_EVENT + 4;
/**
* 实现方法
*
* @param actionCode 事件代码
* @param object 解析好并返回给调用者的最终数据
*/
public abstract void action(int actionCode, Object object);
}
JSONParser的代码如下,它的作用将返回的网络数据由JSONObject格式解析为Bean。这里用到Gson来解析数据,这样的好处是:只用写一份代码,就可以解析任何类型的JSON数据,比如:得到news就解析成NewsBean,得到user就解析成UserBean。而Parser解析器只有一份,极大提高了代码的复用性。
public HashMap<String, Object> parseJSON(String paramString) throws JSONException {
HashMap<String, Object> map = new HashMap<String, Object>();
JSONObject jsonObject = new JSONObject(paramString);
String result = jsonObject.getString("result");
Gson gson = new Gson();
map.put("datamap", gson.fromJson(result, cls));
return map;
JavaBean的格式如下,存放的是一个列表,其中的元素是一个一个的Model。使用Gson,可以轻易地将返回数据中对应的字段解析为Bean中的成员。要注意:返回数据中的字段名应该与Bean中的变量名完全一致,否则无法解析成功。
public class NewsListEntity {
public ArrayList<NewsModel> newsList;
public static class NewsModel {
public int news_id;
public int news_type;
public String news_title;
public String news_sub;
public String news_content;
public String news_imgurl;
public int istop;
public String news_time;
}
}
———主调用函数的使用———
代码如下。展示了主要流程:1.封装请求参数 2. 调用请求函数获取回调数据
protected void getNewsData(int type) {
HttpRequestVo vo = new HttpRequestVo();
vo.requestUrl = ConstantValues.GET_NEWS_LIST;
vo.context = mContext;
HashMap<String, String> map = new HashMap<String, String>();
map.put("istop", "0");
map.put("type", type + "");
vo.requestDataMap = map;
JSONObject requestJson = new JSONObject(); //目前暂时没用
vo.parser = new JSONParser(NewsListEntity.class);
vo.requestJson = requestJson;
getDataFromServer(HttpManager.GET_METHOD, vo, new DataCallback<HashMap<String, Object>>() {
@Override
public void onStart() {
}
@Override
public void onFailed() {
}
/**
* 处理返回的news列表数据
* @param paramObject
*/
@Override
public void processData(HashMap<String, Object> paramObject) {
NewsListEntity newsEntity = (NewsListEntity) paramObject.get("datamap");
ArrayList<NewsListEntity.NewsModel> newsList = newsEntity.newsList;
mList.addAll(newsList);
if (mListView.getAdapter() == null) {
mAdapter = new NewsItemAdapter(getContext(), mList);
mListView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onFinish() {
}
});
}
下面这个就是回调接口。调用方(一般为Activity或Fragment)使用某个请求函数来向服务器请求数据时,要把该接口作为传入参数。
public abstract interface DataCallback<T> {
public abstract void onStart();
public abstract void onFailed();
/**
* 处理服务器返回的数据
*
* @param paramObject 服务器返回的数据实体
*/
public abstract void processData(T paramObject);
public abstract void onFinish();
}
下面的代码展示将回调接口应用在主调用函数中。getDataFromServer这个主调用函数有三个参数,第一个你可以选择GET或POST,第二个是你自己定义的HttpRequestVo请求体,第三个就是上面提到的回调函数,在主调用函数中实现它里面的方法,对返回并解析好的数据进行使用。
/**
* 从服务器上获取数据,并回调处理
*
* @param requestType
* @param requestVo
*/
protected void getDataFromServer(int requestType, HttpRequestVo requestVo, DataCallback callback) {
final BaseHandler handler = new BaseHandler(mContext, callback);
httpManager = new HttpManager(mContext, new HttpRequestListener() {
@Override
public void action(int actionCode, Object object) {
Message msg = Message.obtain();
switch (actionCode) {
case HttpRequestListener.EVENT_NO_NETWORK:
msg.what = HttpRequestListener.EVENT_NO_NETWORK;
break;
case HttpRequestListener.EVENT_NETWORK_ERROR:
msg.what = HttpRequestListener.EVENT_NETWORK_ERROR;
break;
case HttpRequestListener.EVENT_GET_DATA_ERROR:
msg.what = HttpRequestListener.EVENT_GET_DATA_ERROR;
msg.obj = null;
break;
case HttpRequestListener.EVENT_GET_DATA_SUCCESS:
msg.obj = object;
msg.what = HttpRequestListener.EVENT_GET_DATA_SUCCESS;
break;
default:
break;
}
handler.sendMessage(msg);
}
}, requestVo);
callback.onStart();
if (requestType == HttpManager.GET_METHOD) {
/**
*
*/
httpManager.sendGetRequest();
} else if (requestType == HttpManager.POST_METHOD) {
/**
*
*/
httpManager.sendPostRequest();
}
}
下面以GET方法为例,看一下我们是如何发送Http请求的。前面的部分是遍历HttpRequestVo中的参数map,进行url的字符串拼接。拼接完成后,这里我们使用Volley来发送GET请求,这样可以避免书写繁琐的HttpUrlConnection、输入输出流语句,并且不需要另开一个线程,因为多线程代码已经被封装。如果请求成功,在回调函数的onsuccess方法中,需要做两件事:使用parser将请求到的JSONObject解析为Java对象;HttpRequestListener调用action回调方法,将解析结果传回给主调用函数getDataFromServer。
public void sendGetRequest() {
requestStatus = 1;
String urlStr = "";
try {
StringBuffer buffer = new StringBuffer();
buffer.append(requestVo.requestUrl);
if (requestVo.requestDataMap != null) {
if (!buffer.toString().contains("?")) {
buffer.append("?");
} else {
buffer.append("&");
}
HashMap<String, String> map = requestVo.requestDataMap;
int i = 1;
int size = map.size();
for (Map.Entry<String, String> entry : map.entrySet()) {
if (i == size) {
if (TextUtils.isEmpty(entry.getValue())) {
buffer.append(entry.getKey() + "=");
} else {
buffer.append(entry.getKey() + "=" + requestEncodeStr(entry.getValue()));
}
} else {
if (TextUtils.isEmpty(entry.getValue())) {
buffer.append(entry.getKey() + "=" + "&");
} else {
buffer.append(entry.getKey() + "=" + requestEncodeStr(entry.getValue()) + "&");
}
}
i++;
}
}
urlStr = buffer.toString();
VolleyRequest.RequestGet(context, urlStr, "volleyGet",
new VolleyInterface(context, VolleyInterface.mListener, VolleyInterface.mErrorListener) {
@Override
public void onMySuccess(JSONObject result) {
if (result != null) {
try {
if (requestVo.parser != null) {
HashMap<String, Object> map = requestVo.parser.parseJSON(result.toString());
listener.action(HttpRequestListener.EVENT_GET_DATA_SUCCESS, map);
} else {
listener.action(HttpRequestListener.EVENT_GET_DATA_SUCCESS, result);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
@Override
public void onMyError(VolleyError error) {
listener.action(HttpRequestListener.EVENT_NETWORK_ERROR, null);
Log.i("TAG", error.toString());
}
});
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
至此,我们已经获取到了封装好的JavaBean,剩下要做的就是把数据展现在UI上了。