Volley框架的二次封装
jopen
9年前
我们平时开发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框架相当灵活。具体使用哪种方式,就要看你具体的业务需求了。