Volley框架的二次封装

jopen 8年前

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

来自: http://blog.csdn.net/soul_code/article/details/50290691