Volley的二次封裝以及返回泛型的處理

相信大家在平時的開發(fā)中都或多或少的引用一些優(yōu)秀的開源框架來提高項目的開發(fā)速度,那么在使用時,有沒有想過對這些框架進行二次封裝呢,假如你今天使用的是volley,明天項目要求使用retrofit或者asynchttp等其他網(wǎng)絡(luò)框架,那么如果你沒進行二次封裝,那么改起來將會是很痛苦的一件事,每一個調(diào)用網(wǎng)絡(luò)請求的地方你都需要去修改。

本文將對volley進行二次封裝,如果不知道volley為何物或者如何使用的,可以先看郭霖大神博客Android Volley完全解析(一),初識Volley的基本用法再來看本文。

Ok,Let's go!

假設(shè)我們和服務(wù)端約定的返回數(shù)據(jù)格式(這個根據(jù)自身需求定制)為

{"code":"200","msg":"成功","data":{}}

如果我們每次請求都進行解析,那么會出現(xiàn)非常多重復(fù)的代碼,而我們一般都是只關(guān)心data中的數(shù)據(jù),那么我們的目的就是直接通過回調(diào)獲得data中的數(shù)據(jù),至于code的判斷,交給二次封裝中的代碼。

根據(jù)上面的json格式,我們創(chuàng)建對應(yīng)的實體類

public class HttpResult {

    private Object data;
    private int code;
    private String msg;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

我們還需要一個泛型回調(diào)類用于回調(diào)結(jié)果,其中onSuccess是成功回調(diào),onFail是失敗回調(diào)。

public abstract class HttpCallBack<T> {

    public abstract void onSuccess(T data);

    public abstract void onFail(String msg);
}

其中泛型T就是json中data對應(yīng)的數(shù)據(jù),如果data中是一個User實體,那么我們回調(diào)直接寫成HttpCallBack<User>,如果data中是一個User數(shù)組,那么我們回調(diào)直接寫成HttpCallBack<List<User>>,再如果我們只想獲得data中的json字符串,那么就是HttpCallBack<String>。是不是想想都覺得很爽,使用時自己不需要任何的解析。當然,現(xiàn)在只是預(yù)想,這些返回都需要我們在封裝中進行判斷處理。

這里我們使用Gson進行json的解析,使用Gson解析json很簡單,只需要使用public <T> T fromJson(String json, Type typeOfT),其中json參數(shù)無需多說,是json字符串,typeOfT是泛型T的類型,方法返回的是泛型T,這時,我們只需要傳入正確的Type,就可得到我們需要的數(shù)據(jù)然后通過回調(diào)傳出去。

那么問題來了,Type如果獲取呢?在我們的封裝中,我們只需要獲取HttpCallBack<T>中T的類型,怎么獲取呢?答案是ParameterizedType,ParameterizedType 就是形如“ 類型<> ”的類型,如HttpCallBack<T>、List<T>、Map<String,User>。比如Map<String,User>,我們通過getActualTypeArguments()方法可以獲得Type[],里面的內(nèi)容是[String.class,User.class],數(shù)組的長度由< >中的個數(shù)決定。具體代碼如下:

public static Type getTType(Class<?> clazz) {
    Type mySuperClassType = clazz.getGenericSuperclass();
    Type[] types = ((ParameterizedType) mySuperClassType).getActualTypeArguments();
    if (types != null && types.length > 0) {
        //T
        return types[0];
    }
    return null;
}

其中class參數(shù)是HttpCallBack<T>的引用,返回值就是HttpCallBack<T>中T的type。假設(shè)我們的回調(diào)是HttpCallBack<User>,那么返回的Type就是User.class;假設(shè)我們的回調(diào)是HttpCallBack<List<User>>,那么返回的Type就是List<User>,此時再使用上面提到的Gson進行解析,就很輕松了。

接下來就是二次封裝的主要代碼

public class HttpUtil {

    private static HttpUtil mHttpUtil;
    private Gson mGson;

    //請求連接的前綴
    private static final String BASE_URL = "";

    //連接超時時間
    private static final int REQUEST_TIMEOUT_TIME = 60 * 1000;

    //volley請求隊列
    public static RequestQueue mRequestQueue;

    private HttpUtil() {
        mGson = new Gson();
        //這里使用Application創(chuàng)建全局的請求隊列
        mRequestQueue = Volley.newRequestQueue(MyApplication.myApplication);
    }

    public static HttpUtil getInstance() {
        if (mHttpUtil == null) {
            synchronized (HttpUtil.class) {
                if (mHttpUtil == null) {
                    mHttpUtil = new HttpUtil();
                }
            }
        }
        return mHttpUtil;
    }

    /**
     * http請求
     *
     * @param url          http地址(后綴)
     * @param param        參數(shù)
     * @param httpCallBack 回調(diào)
     */
    public <T> void request(String url, final Map<String, String> param, final HttpCallBack<T> httpCallBack) {
        StringRequest stringRequest = new StringRequest(Request.Method.POST, BASE_URL + url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        if (httpCallBack == null) {
                            return;
                        }
                        
                        Type type = getTType(httpCallBack.getClass());

                        HttpResult httpResult = mGson.fromJson(response, HttpResult.class);
                        if (httpResult != null) {
                            if (httpResult.getCode() != 200) {//失敗
                                httpCallBack.onFail(httpResult.getMsg());
                            } else {//成功
                                //獲取data對應(yīng)的json字符串
                                String json = mGson.toJson(httpResult.getData());
                                if (type == String.class) {//泛型是String,返回結(jié)果json字符串
                                    httpCallBack.onSuccess((T) json);
                                } else {//泛型是實體或者List<>
                                    T t = mGson.fromJson(json, type);
                                    httpCallBack.onSuccess(t);
                                }
                            }
                        }
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (httpCallBack == null) {
                    return;
                }
                String msg = error.getMessage();
                httpCallBack.onFail(msg);
            }
        }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                //請求參數(shù)
                return param;
            }

        };
        //設(shè)置請求超時和重試
        stringRequest.setRetryPolicy(new DefaultRetryPolicy(REQUEST_TIMEOUT_TIME, 1, 1.0f));
        //加入到請求隊列
        if (mRequestQueue != null)
            mRequestQueue.add(stringRequest.setTag(url));
    }

    private Type getTType(Class<?> clazz) {
        Type mySuperClassType = clazz.getGenericSuperclass();
        Type[] types = ((ParameterizedType) mySuperClassType).getActualTypeArguments();
        if (types != null && types.length > 0) {
            //T
            return types[0];
        }
        return null;
        }
}

其中,我們規(guī)定了請求全部為post,如果項目中既有post又有g(shù)et,那么可以通過傳參的方式進行設(shè)置。

接下來是如何調(diào)用:

類型一:User

    Map<String, String> param = new HashMap<>();
    param.put("account", "zhijieeeeee");
    param.put("password", "123456");
    HttpUtil.getInstance().request("UserController/login", param, new HttpCallBack<User>() {
        @Override
        public void onSuccess(User user) {
        }

        @Override
        public void onFail(String msg) {
        }
    });

類型二:List<User>

    Map<String, String> param = new HashMap<>();
    param.put("currentPage", "1");
    HttpUtil.getInstance().request("InputController/getUserList", param, new HttpCallBack<List<User>>() {
        @Override
        public void onSuccess(List<User> list) {
        }

        @Override
        public void onFail(String msg) {
        }
    });

類型三:String

    Map<String, String> param = new HashMap<>();
    param.put("currentPage", "1");
    HttpUtil.getInstance().request("CropController/getCropList", param, new HttpCallBack<String>() {
        @Override
        public void onSuccess(String data) {
        }

        @Override
        public void onFail(String msg) {
        }
    });

現(xiàn)在,我們二次封裝全部完成了,假如明天你需要換網(wǎng)絡(luò)請求框架,那么只需要修改HttpUtil中request方法的實現(xiàn)代碼就行,其他調(diào)用HttpUtil.getInstance().request()的地方全部不用修改,很輕松完成了框架的切換。

這里給出依賴的庫

compile 'eu.the4thfloor.volley:com.android.volley:2015.05.28'
compile 'com.google.code.gson:gson:2.2.4'
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,939評論 25 709
  • 1. 功能介紹 1.1. Volley Volley 是 Google 推出的 Android 異步網(wǎng)絡(luò)請求框架和...
    愛碼士平頭哥閱讀 1,921評論 0 9
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,539評論 19 139
  • 注:本文轉(zhuǎn)自http://codekk.com/open-source-project-analysis/deta...
    Ten_Minutes閱讀 1,400評論 1 16
  • 有個哥們零零碎碎提到過西沙群島幾次。 我對它的印象是不知道小學(xué)還是初中課本提到過它,雖然印象中課本說的還挺美,但不...
    八er閱讀 446評論 6 2

友情鏈接更多精彩內(nèi)容