我们平时开发Android app 不可避免的会使用到网络技术,大多数情况下我们都会以http或者https来请求网络数据,而传统的HttpURLConnection、HttpClient,使用起来稍显繁琐。一些网络开发框架也应运而生,今天所要讲的Volley就是其中的一种。个人比较倾向于这个网络框架,究其原因在于他的灵活性。你可以根据你app的架构,对volley进行相应的二次封装,使用起来相当的灵活方便。
在封装之前我们还是来简单了解一下volley, 先贴一个volley的下载地址,volley jar 下载地址
2013年Google I/O大会上推出了一个新的网络通信框架——Volley。Volley可是说是把AsyncHttpClient和Universal-Image-Loader的优点集于了一身,既可以像AsyncHttpClient一样非常简单地进行HTTP通信,也可以像Universal-Image-Loader一样轻松加载网络上的图片。除了简单易用之外,Volley在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。至于Volley的使用,比较简单,不会的同学可以在网上搜搜demo,分分钟就能上手。
鉴于目前大多数网络请求数据格式都是Json ,我们今天就以JsonRequest来讲解一下Volley的二次封装。
第一步:使用Volley之前需要初始化 这步操作建议在Application类中实现
VolleyQueueController.init(getApplicationContext());
第二步:创建访问数据的回调接口
public interface UIDataListener<T> {
void onDataChanged(T data);
void onErrorHappend(String errorMsg);
}
第三步:请求对象的封装
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.json.JSONObject;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.JsonRequest;
/**
* @author Mr.Himan
*
*/
public class NetWorkRequest extends JsonRequest<JSONObject> {
private static final int TIME_OUT = 10000;
public NetWorkRequest(int method, String url,
Map<String, String> postParams, Listener<JSONObject> listener,
ErrorListener errorListener) {
super(method, url, paramstoString(postParams), listener, errorListener);
setRetryPolicy(new DefaultRetryPolicy(TIME_OUT, 0,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
}
public NetWorkRequest(String url, List<NameValuePair> params,
Listener<JSONObject> listener, ErrorListener errorListener) {
this(Method.GET, urlBuilder(url, params), null, listener, errorListener);
}
public NetWorkRequest(String url, Listener<JSONObject> listener,
ErrorListener errorListener) {
this(Method.GET, url, null, listener, errorListener);
}
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
JSONObject jsonObject = new JSONObject(new String(response.data,
"UTF-8"));
return Response.success(jsonObject,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
// 拼接get 请求参数
private static String urlBuilder(String url, List<NameValuePair> params) {
return url + "?" + URLEncodedUtils.format(params, "UTF-8");
}
// 拼接Post请求参数
private static String paramstoString(Map<String, String> params) {
if (params != null && params.size() > 0) {
String paramsEncoding = "UTF-8";
StringBuilder encodedParams = new StringBuilder();
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
encodedParams.append(URLEncoder.encode(entry.getKey(),
paramsEncoding));
encodedParams.append('=');
encodedParams.append(URLEncoder.encode(entry.getValue(),
paramsEncoding));
encodedParams.append('&');
}
return encodedParams.toString();
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: "
+ paramsEncoding, uee);
}
}
return "";
}
}
第四步:构建网络请求Helper
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Handler;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.VolleyError;
import com.css.volunteer.net.volley.NetWorkRequest;
import com.css.volunteer.net.volley.UIDataListener;
import com.css.volunteer.net.volley.VolleyQueueController;
import com.css.volunteer.utils.LoadingWindow;
import com.css.volunteer.utils.MToast;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
/**
* Volley框架的二次封装
*
* @author Mr.Himan
*
*/
public abstract class NetWorkHelper<T> implements
Response.Listener<JSONObject>, ErrorListener {
private Activity mActivity;
private boolean isShowHint = true; // is show the hint message popupWindow
public NetWorkHelper(Activity activity) {
super();
this.mActivity = activity;
}
protected Activity mGetContext() {
return mActivity;
}
/**
* 是否开启加载数据请求的提示框
*/
public void closeShowHint() {
isShowHint = false;
}
protected NetWorkRequest getRequestForGet(String url,
List<NameValuePair> params) {
if (params == null) {
return new NetWorkRequest(url, this, this);
} else {
return new NetWorkRequest(url, params, this, this);
}
}
protected NetWorkRequest getRequestForPost(String url,
Map<String, String> params) {
return new NetWorkRequest(Method.POST, url, params, this, this);
}
public void doHttpGet(String url, List<NameValuePair> params) {
if (isShowHint) {
// 弹出正在加载数据弹框
LoadingWindow.loadingWindow(mActivity, "Loading");
}
NetWorkRequest requestForGet = getRequestForGet(url, params);
requestForGet.setTag(urlBuilder(url, params));
VolleyQueueController.getInstance().cancelAll(urlBuilder(url, params));
VolleyQueueController.getInstance().add(requestForGet);
}
/**
* get请求
*
* @param url
*/
public void doHttpGet(String url) {
doHttpGet(url, null);
}
private static String urlBuilder(String url, List<NameValuePair> params) {
if (params == null) {
return url;
}
return url + "?" + URLEncodedUtils.format(params, "UTF-8");
}
/**
* post请求
*
* @param url
*/
public void doHttpPost(String url, Map<String, String> params) {
VolleyQueueController.getInstance().add(getRequestForPost(url, params));
}
@Override
public void onErrorResponse(VolleyError error) {
if (isShowHint) {
LoadingWindow.closeWindow();
}
showErrorMsg();
disposeVolleyError(error);
}
protected abstract void disposeVolleyError(VolleyError error);
@Override
public void onResponse(JSONObject response) {
if (isShowHint) {
LoadingWindow.closeWindow();
}
if (response != null) {
disposeResponse(response);
} else {
showErrorMsg();
}
}
/**
* 数据加载错误提示
*/
protected void showErrorMsg() {
}
protected abstract void disposeResponse(JSONObject response);
private UIDataListener<T> dataListener;
public void setDataListener(UIDataListener<T> dataListener) {
this.dataListener = dataListener;
}
protected void notifyDataChanged(T data) {
if (dataListener != null) {
dataListener.onDataChanged(data);
}
}
protected void notifyErrorHappened() {
if (dataListener != null) {
dataListener.onErrorHappend();
}
}
}
到这里Volley的二次封装就完成了,看下使用
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import com.android.volley.VolleyError;
import com.css.volunteer.manager.DialogManager;
import com.css.volunteer.net.NetWorkHelper;
import com.css.volunteer.utils.MToast;
public abstract class UserNetHelper<User> extends NetWorkHelper<T> {
public UserNetHelper(Activity context) {
super(context);
}
@Override
protected void disposeVolleyError(VolleyError error) {
onErrorHappend(error);
}
@Override
protected void disposeResponse(JSONObject response) {
// 解析数据获取bean
String userName = response.getString("userName");
String userSex = response.getString("userSex");
User user = new User(userName,userSex);
notifyDataChanged(user);
}
@Override
protected void showErrorMsg() {
// 统一错误提示信息处理
}
}
public LoginActivity extends Activity{
...代码省略...
public void getUserInfo(){
UserNetHelper userNetHelper =new UserNetHelper(this);
userNetHelper.setDataListener(new UIDataListener<User>() {
@Override
public void onDataChanged(User data) {
// 获取user
}
<pre name="code" class="java"> @Override
public void onErrorHappend(User data) {
// 获取数据失败
}
});
userNetHelper.doHttpGet("url 地址");
}
}
从上面的小Demo可以看到,封装之后,在Activity里面的代码非常简介,只有短短几行代码。判断当前网络状态都可以在Helper中统一处理。想请求是否具备权限,操作是否成功,获取手机验证码返回结果单一的情况下,代码复用性是相当高的。同样你也可以根据业务需求定制数据自己的helper,可以看到我们在Helper类中传入的Activity对象,你完全可以把一个带下拉的ListView封装到Helper中,再凡是使用到列表加载的逻辑,只需改动请求url 和 数据类型的解析,像分页加载,上拉下拉等操作都可统一处理,可以极大的节约开发时间。但这样的缺陷也显而易见,Helper中持有Activity对象的强引用,因为网络请求是异步操作,当你在请求网络的时候Activity可能已经被销毁了,这里处理不当可能会造成内存泄漏。你也可以在封装Helper类的时候不传入Activity对象,像现在主流的MVP模式下,Model层和View是完全分离的,如果你使用的是基于MVP的开发模式,在创建Helper类的时候就不能传入Activity对象了,那会造成Model层和VIew层的耦合,关于MVP模式下的Volley可以参照这篇帖子 Android中的MVP模式。你也可以加入Handler进行封装,总而言之,Voller框架相当灵活。具体使用哪种方式,就要看你具体的业务需求了。