Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Volley+OkHttp3+Gson 開源庫的封裝

Android Volley+OkHttp3+Gson 開源庫的封裝

編輯:關於Android編程

博客將按照下面的步驟介紹Volley的重新封裝:
1.OkHttp3的關於Volley的HttpStack實現
2.HttpRequest的實現和HttpListener回調監聽的封裝
3.Volley原始的Request的Wrap
4.各種方式的請求的重新實現
5.統一請求的實現
6.使用

所需依賴:

compile 'com.android.volley:volley:1.0.0'
compile 'com.squareup.okio:okio:1.7.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.google.code.gson:gson:2.6.2'

一、OkHttp3Stack的關於Volley的實現

這個是應該是比較簡單的,關於OkHttp3Stack的實現在github上面有實現,本博客裡面的實現在我的Github上面。
由於代碼比較長,而且這個也不是這篇博客的重點,大家需要的話可以去我的Github查看。

二、HttpRequest的實現和HttpListener回調監聽的封裝

2.1.HttpRequest的實現

通過查看Volley的源代碼我們會發現,Volley的Request的構造方法是這樣寫的:

    public Request(int method, String url, Response.ErrorListener listener) {
        mMethod = method;
        mUrl = url;
        mErrorListener = listener;
        setRetryPolicy(new DefaultRetryPolicy());
        mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
    }

請求的參數有一些通過構造方法傳遞,而另外一些參數是通過Request裡面的很多的get方法得到的,比如post請求的時候的參數是通過Request類裡面的getParams()實現的,而我們需要做的就是如果需要post請求,那麼就重寫請求類,覆蓋裡面的getParams方法。

    protected Map getParams() throws AuthFailureError {
        return null;
    }

會發現這樣並不利於統一的調度,那其實在構造一個請求的時候,參數是不固定的,而且有的需要,有的不需要,這個時候,我們可以通過Builder模式來構造請求,可以進行如下的封裝:

package com.yong.volleyok;

/**
 * Project: com.yong.volleyok 

 * Create Date: 2016/4/22 

 * Author: qingyong 

 * Description: 請求的封裝,使用Builder模式進行構建 

 */
public class HttpRequest {

    private Builder mBuilder;

    private HttpRequest(Builder builder) {
        this.mBuilder = builder;
    }

    public Map getHeaders() {
        return mBuilder.headMaps;
    }

    public int getMethod() {
        return mBuilder.method;
    }

    public Map getParams() {
        return mBuilder.params;
    }

    public Request.Priority getPriority() {
        return mBuilder.priority;
    }

    public String getContentType() {
        return mBuilder.contentType;
    }

    public String getParamsEncodeing() {
        return mBuilder.paramsEncodeing;
    }

    public RetryPolicy getRetryPolicy() {
        return mBuilder.retryPolicy;
    }

    public String getUrl() {
        return mBuilder.url;
    }

    public static final class Builder {

        String paramsEncodeing = "UTF-8";
        String url;
        int method = Request.Method.GET;
        Request.Priority priority = Request.Priority.NORMAL;
        String contentType = "application/x-www-form-urlencoded; charset=utf-8";
        // 請求頭
        Map headMaps = new HashMap<>();
        // 參數
        Map params = new HashMap<>();

        // 超時以及重連次數
        RetryPolicy retryPolicy = new DefaultRetryPolicy(10000, 2, 1.0F);

        public Builder(String url) {
            this.url = url;
        }

        /**
         * 增加 Http 頭信息
         *
         * @param key   key
         * @param value value
         * @return
         */
        public Builder addHeader(String key, String value) {
            this.headMaps.put(key, value);
            return this;
        }

        /**
         * 增加 Http 頭信息
         *
         * @param headers
         * @return
         */
        public Builder addheader(Map headers) {
            for (Map.Entry entry : headers.entrySet()) {
                this.headMaps.put(entry.getKey(), entry.getValue());
            }
            return this;
        }

        /**
         * 設置 Http 請求方法
         *
         * @param method {@link Request.Method}
         * @return
         */
        public Builder setMethod(int method) {
            this.method = method;
            return this;
        }

        /**
         * 增加請求參數
         *
         * @param key   key
         * @param value value
         * @return
         */
        public Builder addParam(String key, Object value) {
            this.params.put(key, String.valueOf(value));
            return this;
        }

        /**
         * 增加請求參數
         *
         * @param params map
         * @return
         */
        public Builder addParam(Map params) {
            for (Map.Entry entry : params.entrySet()) {
                this.params.put(entry.getKey(), String.valueOf(entry.getValue()));
            }
            return this;
        }

        /**
         * 設置請求優先級
         *
         * @param priority {@link Request.Priority}
         * @return
         */
        public Builder setPriority(Request.Priority priority) {
            this.priority = priority;
            return this;
        }

        /**
         * 設置文本類型
         *
         * @param contentType
         * @return
         */
        public Builder setContentType(String contentType) {
            this.contentType = contentType;
            return this;
        }

        /**
         * 設置超時以及重連次數
         *
         * @param initialTimeoutMs  超時時間
         * @param maxNumRetries     重連次數
         * @param backoffMultiplier
         * @return
         */
        public Builder setRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {
            this.retryPolicy = new DefaultRetryPolicy(initialTimeoutMs, maxNumRetries, backoffMultiplier);
            return this;
        }

        /**
         * 構建 HttpRequest
         *
         * @return
         */
        public HttpRequest build() {
            return new HttpRequest(this);
        }

    }

}

我們構造這樣的一個請求的類,然後在請求的時候可以通過這個類,去構建請求的時候需要的一些參數。這個類很簡單就不用詳細的講解了。具體的怎麼使用這個類去構造請求,我們會在Wrap Volley的Request的時候詳細的說明。

2.2.HttpListener的封裝

其實就是回調的封裝,在Volley裡面是使用了兩個接口來做的,這裡統一成一個接口。

package com.yong.volleyok;

/**
 * Project: com.yong.volleyok 

 * Create Date: 2016/4/22 

 * Author: qingyong 

 * Description: 回調響應 

 */
public interface HttpListener {
    /**
     * 服務器響應成功
     *
     * @param result 響應的理想數據。
     */
    void onSuccess(T result);

    /**
     * 網絡交互過程中發生錯誤
     *
     * @param error {@link VolleyError}
     */
    void onError(VolleyError error);
}

將成功和失敗的回調封裝到一個方法裡面了。

三、Request的Wrap

為了以後能更好的升級的考慮,我們最好是不采用直接改源代碼的方式,所以我們只能對原始的請求類Request類進行Wrap,然後我們自定義請求類繼承這個Wrap的類。先貼代碼,然後講解。

package com.yong.volleyok.request;

/**
 * Project: com.yong.volleyok 

 * Create Date: 2016/4/22 

 * Author: qingyong 

 * Description: 原始請求的包裝 

 */
public abstract class RequestWrapper extends com.android.volley.Request {

    /**
     * 請求
     */
    protected HttpRequest mHttpRequest;

    /**
     * 結果
     */
    protected HttpListener mHttpListener;

    public RequestWrapper(HttpRequest httpRequest, HttpListener listener) {
        // 這裡不需要錯誤的監聽,下面已經做了處理
        super(httpRequest.getMethod(), httpRequest.getUrl(), null);
        this.mHttpRequest = httpRequest;
        this.mHttpListener = listener;
    }

    /**
     * 得到url,這裡get方法作處理,把參數都拼接上去
     *
     * @return
     */
    @Override
    public String getUrl() {
        // 當get的時候做處理,把參數都連接起來
        try {
            if (getMethod() == Method.GET &&
                    (getParams() != null && getParams().size() != 0)) {
                String encodedParams = getEncodedUrlParams();
                String extra = "";
                if (encodedParams != null && encodedParams.length() > 0) {
                    if (!mHttpRequest.getUrl().endsWith("?")) {
                        extra += "?";
                    }
                    extra += encodedParams;
                }
                return mHttpRequest.getUrl() + extra;
            }
        } catch (AuthFailureError e) {
        }
        return mHttpRequest.getUrl();

    }

    /**
     * 拼接get請求的參數的拼接
     *
     * @return
     * @throws AuthFailureError
     */
    public String getEncodedUrlParams() throws AuthFailureError {
        StringBuilder encodedParams = new StringBuilder();
        String paramsEncoding = getParamsEncoding();
        Map params = getParams();
        try {
            for (Map.Entry entry : params.entrySet()) {
                if (null == entry.getValue()) {
                    continue;
                }
                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
     * @throws AuthFailureError
     */
    @Override
    public Map getHeaders() throws AuthFailureError {
        return mHttpRequest.getHeaders();
    }

    /**
     * 請求參數
     *
     * @return
     * @throws AuthFailureError
     */
    @Override
    protected Map getParams() throws AuthFailureError {
        return mHttpRequest.getParams();
    }

    /**
     * 請求的ContentType
     *
     * @return
     */
    @Override
    public String getBodyContentType() {
        return mHttpRequest.getContentType();
    }

    /**
     * 請求的優先級,這裡RequestQueue裡面會根據這個把請求進行排序
     *
     * @return
     */
    @Override
    public Priority getPriority() {
        return mHttpRequest.getPriority();
    }

    /**
     * 設置請求時長,請求失敗之後的次數
     *
     * @return
     */
    @Override
    public RetryPolicy getRetryPolicy() {
        return mHttpRequest.getRetryPolicy();
    }

    /**
     * 請求成功
     *
     * @param response The parsed response returned by
     */
    @Override
    protected void deliverResponse(T response) {
        if (mHttpListener != null) {
            mHttpListener.onSuccess(response);
        }
    }

    /**
     * 請求失敗
     *
     * @param error Error details
     */
    @Override
    public void deliverError(VolleyError error) {
        if (mHttpListener != null) {
            mHttpListener.onError(error);
        }
    }

}

這裡最重要的就是這個類了,下面詳細的說一下,封裝的過程:
我們在前面定義了HttpRequest和HttpListener類就是為了在這裡使用,在構造方法裡面把這兩個傳遞進來,然後請求需要的參數通過HttpRequest的一系列的get方法獲取,請求最終的回調通過HttpListener傳遞出去。

首先來看HttpListener的最終的兩個回調的方法:

    @Override
    protected void deliverResponse(T response) {
        if (mHttpListener != null) {
            mHttpListener.onSuccess(response);
        }
    }
    @Override
    public void deliverError(VolleyError error) {
        if (mHttpListener != null) {
            mHttpListener.onError(error);
        }
    }

這兩個方法一個是請求成功的方法,另外一個是請求失敗的方法,我們通過HttpListener把最後的結果拋出去,這裡可以統一實現,不需要子請求類再去實現了。

再看其余的一些方法,getUrl方法是請求的url,但是我們在封裝請求的時候不管是get還是post都是把參數放置getParams方法裡面返回的,get請求是直接使用url拼接參數的,所以需要對這個方法進行重寫,這樣,才能保證get請求能有參數。

getHeaders是請求頭,這裡直接使用HttpRequest獲取到。

getParams時請求的參數,也是直接通過HttpRequest拿到。

其余的方法都是大同小異,總體來說這個封裝也比較簡單的。

四、各種方式的請求的重新實現

上面對Request進行了重新的封裝之後,我們只需要繼承RequestWrapper即可,並且,需要我們實現的方法也只有一個了,parseNetworkResponse。由於我們隊Request進行了封裝,所以Volley自己帶的幾個請求,如JsonRequest,StringRequest等,都需要重寫,繼承RequestWrapper,但是,經過我們的封裝,重寫不會很麻煩。
這裡只舉兩個例子,一個ByteRequest:

package com.yong.volleyok.request;

/**
 * Project: com.yong.volleyok.request 

 * Create Date: 2016/4/23 

 * Author: qingyong 

 * Description: Byte Request 

 */
public class ByteRequest extends RequestWrapper {

    public ByteRequest(HttpRequest httpRequest, HttpListener listener) {
        super(httpRequest, listener);
    }

    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
    }
}

可以看到經過我們的封裝之後,實現變得非常簡單了。

GsonRequest:

package com.yong.volleyok.request;

/**
 * Project: com.yong.volleyok.request 

 * Create Date: 2016/4/23 

 * Author: qingyong 

 * Description: Gson Request 

 */
public class GsonRequest extends RequestWrapper {

    private static Gson mGson = new Gson();
    private Class mClass;
    private TypeToken mTypeToken;

    public GsonRequest(Class tClass, HttpRequest httpRequest, HttpListener listener) {
        this(tClass, null, httpRequest, listener);
    }

    public GsonRequest(Class tClass, TypeToken typeToken,
                       HttpRequest httpRequest, HttpListener listener) {
        super(httpRequest, listener);
        mClass = tClass;
        mTypeToken = typeToken;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Response parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(
                    response.data, HttpHeaderParser.parseCharset(response.headers, getParamsEncoding()));
            if (mTypeToken == null) {
                return Response.success(
                        mGson.fromJson(json, mClass), HttpHeaderParser.parseCacheHeaders(response));
            } else {
                return (Response) Response.success(
                        mGson.fromJson(json, mTypeToken.getType()), HttpHeaderParser.parseCacheHeaders(response));
            }
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }
}

這裡只貼出這兩個方法,還有的方法可以看github。

五、統一請求的實現

請求都封裝好了,現在只有調用了,針對封裝的6種請求可以封裝一個接口。

package com.yong.volleyok;

/**
 * Project: com.yong.volleyok 

 * Create Date: 2016/4/23 

 * Author: qingyong 

 * Description: 請求 

 */
public interface IHttpClient {

    /**
     * byte請求
     */
    Request byteRequest(HttpRequest httpRequest, HttpListener listener, Object tag);

    /**
     * String請求
     */
    Request stringRequest(HttpRequest httpRequest, HttpListener listener, Object tag);

    /**
     * gzip請求
     */
    Request gZipRequest(HttpRequest httpRequest, HttpListener listener, Object tag);

    /**
     * JsonObject請求
     * @return
     */
    Request jsonObjectRequest(String requestBody, HttpRequest httpRequest, HttpListener listener, Object tag);

    /**
     * JsonArray請求
     */
    Request jsonArrayRequest(String requestBody, HttpRequest httpRequest, HttpListener listener, Object tag);

    /**
     * Gson請求,可以映射Model
     */
     Request gsonRequest(Class tClass, TypeToken typeToken, HttpRequest httpRequest, HttpListener listener, Object tag);
}

然後再寫一個具體的實現類即可。

package com.yong.volleyok;

/**
 * Project: com.yong.volleyok.http 

 * Create Date: 2016/4/23 

 * Author: qingyong 

 * Description: 請求的具體實現類 

 */
public class HttpClient implements IHttpClient {

    private static HttpClient INSTANCE;
    private static final int[] sLock = new int[0];

    private final RequestQueue mRequestQueue;
    private final Context mContext;

    private HttpClient(Context context) {
        mContext = context;
        mRequestQueue = Volley.newRequestQueue(context,
                new OkHttp3Stack(new OkHttpClient()));
    }

    /**
     * 這裡使用Application的Context
     *
     * @param context
     * @return
     */
    public static HttpClient getInstance(Context context) {
        if (null == INSTANCE) {
            synchronized (sLock) {
                if (null == INSTANCE) {
                    INSTANCE = new HttpClient(context);
                }
            }
        }
        return INSTANCE;
    }

    /**
     * 添加請求
     *
     * @param request
     */
    public void addRequest(Request request, Object tag) {
        if (tag != null) {
            request.setTag(tag);
        }
        mRequestQueue.add(request);
    }

    /**
     * 取消請求
     *
     * @param tag
     */
    public void cancelRequest(Object tag) {
        mRequestQueue.cancelAll(tag);
    }

    public Request ByteRequest(HttpRequest httpRequest, HttpListener listener) {
        return byteRequest(httpRequest, listener, null);
    }

    @Override
    public Request byteRequest(HttpRequest httpRequest, HttpListener listener, Object tag) {
        ByteRequest request = new ByteRequest(httpRequest, listener);
        addRequest(request, tag);
        return request;
    }

    public Request stringRequest(HttpRequest httpRequest, HttpListener listener) {
        return stringRequest(httpRequest, listener, null);
    }

    @Override
    public Request stringRequest(HttpRequest httpRequest, HttpListener listener, Object tag) {
        StringRequest request = new StringRequest(httpRequest, listener);
        addRequest(request, tag);
        return request;
    }

    public Request gZipRequest(HttpRequest httpRequest, HttpListener listener) {
        return gZipRequest(httpRequest, listener, null);
    }

    @Override
    public Request gZipRequest(HttpRequest httpRequest, HttpListener listener, Object tag) {
        GZipRequest request = new GZipRequest(httpRequest, listener);
        addRequest(request, tag);
        return request;
    }

    public Request jsonObjectRequest(HttpRequest httpRequest, HttpListener listener) {
        return jsonObjectRequest(null, httpRequest, listener);
    }

    public Request jsonObjectRequest(String requestBody, HttpRequest httpRequest, HttpListener listener) {
        return jsonObjectRequest(requestBody, httpRequest, listener, null);
    }

    @Override
    public Request jsonObjectRequest(String requestBody, HttpRequest httpRequest, HttpListener listener, Object tag) {
        JsonObjectRequest request = new JsonObjectRequest(requestBody, httpRequest, listener);
        addRequest(request, tag);
        return request;
    }

    public Request jsonArrayRequest(HttpRequest httpRequest, HttpListener listener) {
        return jsonArrayRequest(httpRequest, listener, null);
    }

    public Request jsonArrayRequest(HttpRequest httpRequest, HttpListener listener, Object tag) {
        return jsonArrayRequest(null, httpRequest, listener, tag);
    }

    @Override
    public Request jsonArrayRequest(String requestBody, HttpRequest httpRequest, HttpListener listener, Object tag) {
        JsonArrayRequest request = new JsonArrayRequest(requestBody, httpRequest, listener);
        addRequest(request, tag);
        return request;
    }

    public  Request gsonRequest(Class tClass, HttpRequest httpRequest, HttpListener listener) {
        return gsonRequest(tClass, httpRequest, listener, null);
    }

    public  Request gsonRequest(Class tClass, HttpRequest httpRequest, HttpListener listener, Object tag) {
        return gsonRequest(tClass, null, httpRequest, listener, tag);
    }

    @Override
    public  Request gsonRequest(Class tClass, TypeToken typeToken,
                                   HttpRequest httpRequest, HttpListener listener, Object tag) {
        GsonRequest request = new GsonRequest(tClass, typeToken, httpRequest, listener);
        addRequest(request, tag);
        return request;
    }
}

六、使用
當然使用也非常簡單,看HttpClient就知道有哪些方法。

        mResult = (TextView) findViewById(R.id.result);
        mHttpClient = HttpUtil.getHttpClient();
        HttpRequest request = new HttpRequest.Builder("http://www.mocky.io/v2/571b3c270f00001a0faddfcc")
                .setMethod(Request.Method.GET)
                .build();
        mHttpClient.stringRequest(request, new HttpListener() {
            @Override
            public void onSuccess(String result) {
                Log.e("TAG", result);
                mResult.setText(result);
            }

            @Override
            public void onError(VolleyError error) {
                mResult.setText(error.getMessage());
            }
        });

庫和Demo地址:
https://github.com/qingyongai/VolleyOkExtension

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved