Volley框架的二次封裝

jopen 10年前發布 | 60K 次閱讀 Android開發 移動開發

     我們平時開發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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!