Okhttp3網絡請求框架簡析思考——Android網絡請求框架(五)

站在世界的巔峯看世界的心情,決不是一個普通人可以體會的到的感受java

一、對單例設計模式的思考 

建立方式一 、

/**
 * Created by androidlongs on 16/9/12.
 * 站在頂峯,看世界
 * 落在谷底,思人生
 */

/**
 * 建立方式一:
 * 
 * 當在JVM在加載單例類的時候,單例對象就會被創建
 * 當其中有其餘的靜態方法的時候,使用類調用方法,沒有使用到該單例對象,可是單例對象也會被建立出來,從而形成了資源的浪費
 */
public class Singleton {
    //直接建立
    public static  Singleton sSingleton = new Singleton();
    //私有構造函數
    private Singleton(){

    }
    //返回對象體
    public static Singleton getInstance(){
        return sSingleton;
    }
    //獲取String的方法
    public static String getString(){
        return "single";
    }

}

建立方式 二

/**
 * Created by androidlongs on 16/9/12.
 * 站在頂峯,看世界
 * 落在谷底,思人生
 */

/**
 * 建立方式二
 *
 * 有點性能上的損失
 */
class SingletonLazy{
    //聲明變量
    public static  SingletonLazy sSingletonLazy;
    //私有構造函數
    private SingletonLazy(){

    }
    //提供對外方法
    public static  SingletonLazy getInstance(){
        if (sSingletonLazy == null) {
            synchronized (SingletonLazy.class){
                if (sSingletonLazy == null) {
                    sSingletonLazy = new SingletonLazy();
                }
            }
        }
        return sSingletonLazy;
    }

    //獲取String的方法
    public static  String getString(){
        return "single";
    }


}

建立方式三:

/**
 * 建立方式三
 */
class  CommonSingleton{
    //私有構造
    private CommonSingleton(){

    }
    //提供對外方法
    public static CommonSingleton getInstance(){
        return  SingletonHolder.commonSingleton;
    }
    //內部類方法維護
    private static class SingletonHolder{
        private static CommonSingleton commonSingleton = new CommonSingleton();
    }
    //獲取String的方法
    public static String getString(){
        return "single";
    }

}

分析 簡述:android

    1-一、能夠看到上面三種建立單例的方法,第一種方式被傳統命名爲餓漢式,單例對象隨着類的加載而被建立,當咱們使用類中的其餘靜態方法而沒有使用到單例對象的時候,單例對象依然會被建立出來,從某種角度來講,形成了必定的內存浪費。json

    1-二、第二種方式被傳統命名爲懶漢式,也就是在調用實例化對象的時候,纔會將單例對象建立出來,當咱們使用類中的其餘靜態方法的時候,會同時有單例對象的null引用生成,在必定程度上會很消耗內存,再者建立實例化對象的時候,雙重非空鎖判斷,也是至關消耗性能的工做。設計模式

    1-三、第三種方式能夠稱爲是完美設計版了,由於它能夠解決前兩種設計方法的不足之處,當去調用類的實例化方法的時候,單例對象纔會被建立,而當調用類中的其餘靜態方法的時候,對靜態單例對象沒有任何的操做,因此能夠說是比較完美的了,之因此能夠稱爲比較而不是徹底,是因使用這種方式建立,在進行序列化與反序列化的時候,會出現非單例對象問題。緩存

二、使用單例設計模式來建立Okhttp網絡請求框架

/**
 * Created by androidlongs on 16/9/12.
 * 站在頂峯,看世界
 * 落在谷底,思人生
 */
public class CommonOkhttpUtils {
    //私有化構造
    private CommonOkhttpUtils(){
        //初始化Okhttp配製
        initOkHttpFunction();
    }

    //提供實例化對象 
    public static CommonOkhttpUtils getUtilsInstance(){
        return  OkHttpSingle.sCommonOkhttpUtils;
    }
    //實例靜態內部類
    private static class OkHttpSingle{
        private static CommonOkhttpUtils sCommonOkhttpUtils = new CommonOkhttpUtils();
    }


    //初始化Okhttp配製
    private void initOkHttpFunction() {
        
    }
}

固然在使用Okhttp3的時候 要先關聯依賴markdown

compile 'com.squareup.okhttp3:okhttp:3.3.1'

三、對Okhttp3進行的一些初始化配製 

private OkHttpClient mOkHttpClient;
    //初始化Okhttp配製
    private void initOkHttpFunction() {
        //配製網絡數據緩存
        File cacheDirectory = APPApplication.getmContext().getExternalCacheDir();
        //配製網絡數據緩存大小  10M
        int cacheSize = 10*1024*1024;
        //
        Cache cache = new Cache(cacheDirectory,cacheSize);
        //建立HttpClientBuilder
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        //設置緩存 以及超時間 以及獲取OkHttpClient對象
        mOkHttpClient = builder.writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .cache(cache)
                .build();
    }

四、網絡請求思路綜述

    其實建立一個網絡鏈接並無多複雜網絡

    4-1 建立請求Request對象 app

    4-2建立封裝參數的RequestBody對象(GET方法除外)框架

    4-3 封裝請求參數 異步

    4-4 建立請求Response對象實例

    4-5 發起網絡請求

    4-6 處理回調監聽

    4-7 處理取消網絡請求標籤    

五、GET異步請求(可傳參數 )

/**
     * 異步GET網絡請求
     *
     * @param url          請求網絡連接
     * @param headerMap    請求網絡添加頭信息
     * @param paramsMap    請求網絡參數
     * @param cacheControl 緩存模式
     *                    
     *                     public static final CacheControl FORCE_NETWORK = ..;
     *                     
     *                     public static final CacheControl FORCE_CACHE = ...
     * @param callback     響應回調
     * @param tag          網絡任務標識
     */
    public void okHttpGetRequest(String url, Map<String, String> headerMap, Map<String, String> paramsMap, CacheControl cacheControl, Callback callback, String tag) {

        //GET請求-1 封裝請求參數 
        //Get請求傳參數其實是在請求連接中攜帶參數 
        StringBuilder sb = new StringBuilder();
        sb.append(url).append("?");
        
        if (paramsMap != null && !paramsMap.isEmpty()) {
            for (String key : paramsMap.keySet()) {
                sb.append(key).append("=").append(paramsMap.get(key)).append("&");
            }
            sb = sb.deleteCharAt(sb.length() - 1);
            url = sb.toString();
        }
        
        //GET請求-2 獲取Builder
        Request.Builder builder = new Request.Builder().url(url);
        
        //GET請求-3 設置緩存
        if (cacheControl != null) {
            builder.cacheControl(cacheControl);
        }
        //GET請求-4添加請求頭信息
        if (headerMap != null && !headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        //GET請求-5 建立請求Request對象 
        Request request = builder.build();
        //GET請求-6 設置取消標籤
        Call call = mOkHttpClient.newCall(request);
        //將請求標籤添加到請求Key集合中
        mCallHashMap.put(tag, call);
        //GET請求-5 發起網絡請求
        call.enqueue(callback);
    }

    /**
     * 移除 取消網絡任務
     *
     * @param tag
     */
    public void removeRequest(String tag) {
        //獲取KEY的集合
        Set<Map.Entry<String, Call>> keyEntries = mCallHashMap.entrySet();
        //若是包含KEY
        if (keyEntries.contains(tag)) {
            //獲取對應的Call
            Call call = mCallHashMap.get(tag);
            //若是沒有被取消 執行取消的方法
            if (!call.isCanceled()) {
                call.cancel();
            }
            //移除對應的KEY
            mCallHashMap.remove(tag);
        }
    }

這是GET請求參數最多的方法,咱們能夠在此基礎上封裝少參數的方法,例如不須要設置請求頭,請求參數,不指定緩存模式,對應的傳入null就能夠。這裏實際上就是將傳入的參數以KEY - VALUE的方式拼接在了請求連接中

對於網絡請求模式,默認有兩種,一是強制使用網絡請求數據 ,一是強制使用緩存,通常使用默認使用網絡請求就能夠

使用案例 :

//GET訪問
    private void getRequestFunction() {
        //請求連接
        String url = "";
        //網絡請求標識
        String tag = "getRequest";

        //提交參數 
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("userName", "xxx");
        paramMap.put("password", "123456");


        //添加請求Header 
        Map<String, String> heardMap = new HashMap<>();
        heardMap.put("verson", "11");


        CommonOkhttpUtils.getUtilsInstance().okHttpGetRequest(url, heardMap, paramMap, CacheControl.FORCE_NETWORK, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            //請求失敗回調方法
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            //請求成功回調方法
            }
        }, tag);
    }
    
    
    //取消網絡請求
    private void canlaneRequest(String tag){
        CommonOkhttpUtils.getUtilsInstance().removeRequest(tag);
    }

經過抓包能夠看到咱們提交的請求數據爲

六、POST異步請求提交表單數據 

/**
     * 異步POST網絡請求  提交表單數據
     *
     * @param url          請求網絡連接
     * @param headerMap    請求網絡添加頭信息
     * @param parmMap    請求網絡參數
     * @param cacheControl 緩存模式
     *                     public static final CacheControl FORCE_NETWORK = ..;
     *                    
     *                     public static final CacheControl FORCE_CACHE = ...
     * @param callback     響應回調
     * @param tag          網絡任務標識
     */
    public void okPostFormRequest(String url, Map<String, String> headerMap, Map<String, String> parmMap, CacheControl cacheControl, Callback callback, String tag) {
        //POST - FORM 表單 獲取請求參數BODY
        FormBody.Builder formBuilder = new FormBody.Builder();

        //POST - FORM 表單 封裝參數
        if (parmMap != null && !parmMap.isEmpty()) {
            for (Map.Entry<String, String> entry : parmMap.entrySet()) {
                formBuilder.add(entry.getKey(), entry.getValue());
            }
        }

        //POST - FORM 獲取表單BODY
        RequestBody formBody = formBuilder.build();
        //POST - FORM 構建請求Request Builder
        Request.Builder requestBuilder = new Request.Builder().url(url);

        //POST - FORM 設置緩存

        if (cacheControl != null) {
            requestBuilder.cacheControl(cacheControl);
        }

        //POST - FORM 添加請求頭信息
        if (headerMap != null && !headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry :
                    headerMap.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        //POST - FORM 構建請求Request
        Request request = requestBuilder.post(formBody).build();
        //POST - FORM 構建請求響應Call
        Call call = mOkHttpClient.newCall(request);
        //POST - FORM 設置取消任務標籤 
        mCallHashMap.put(tag,call);
        //POST - FORM 發起請求
        call.enqueue(callback);
    }

    /**
     * 移除 取消網絡任務
     *
     * @param tag
     */
    public void removeRequest(String tag) {
        //獲取KEY的集合
        Set<Map.Entry<String, Call>> keyEntries = mCallHashMap.entrySet();
        //若是包含KEY
        if (keyEntries.contains(tag)) {
            //獲取對應的Call
            Call call = mCallHashMap.get(tag);
            //若是沒有被取消 執行取消的方法
            if (!call.isCanceled()) {
                call.cancel();
            }
            //移除對應的KEY
            mCallHashMap.remove(tag);
        }
    }
}

案例:

private void postRequestForm() {
        //請求連接
        String url = "http://192.168.1.107:8080/OkhttpAppLication/test";
        //網絡請求標識
        String tag = "getRequest";

        //提交參數
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("userName", "xxx");
        paramMap.put("password", "123456");


        //添加請求Header
        Map<String, String> heardMap = new HashMap<>();
        heardMap.put("verson", "11");
        CommonOkhttpUtils.getUtilsInstance().okPostFormRequest(url, heardMap, paramMap, CacheControl.FORCE_NETWORK, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請求失敗回調方法
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請求成功回調方法
            }
        }, tag);
    }

經過抓包工具能夠看到提交的數據爲:

提交數據的格式爲: Content - Type:application/x-www-form-urlencoded

添加的請求頭爲 verson : 11

提交的參數爲:

七、POST異步請求提交JSON數據 

/**
     * 異步POST網絡請求 提交JSON數據 
     *
     * @param url          請求網絡連接
     * @param headerMap    請求網絡添加頭信息
     * @param parmMap    請求網絡參數
     * @param cacheControl 緩存模式
     *                     public static final CacheControl FORCE_NETWORK = ..;
     *                    
     *                     public static final CacheControl FORCE_CACHE = ...
     * @param callback     響應回調
     * @param tag          網絡任務標識
     */
    public void okPostJSONRequest(String url, Map<String, String> headerMap, Map<String, String> parmMap, CacheControl cacheControl, Callback callback, String tag) {
        //獲取Builder 
        Request.Builder builder = new Request.Builder().url(url);
       // 設置緩存
        if (cacheControl != null) {
            builder.cacheControl(cacheControl);
        }
     
       //添加請求頭信息
        if (headerMap != null && !headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        /**
         * 封裝參數
         */
        JSONObject jsonObject = new JSONObject();
        if (parmMap != null && !parmMap.isEmpty()) {
            for (Map.Entry<String, String> entry :parmMap.entrySet()) {
                try {
                    jsonObject.put(entry.getKey(), entry.getValue());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
       
        //獲取RequestBody
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonObject.toString());
        //獲取 Request
        Request request = builder.post(requestBody).build();
        //獲取Call
        Call call = mOkHttpClient.newCall(request);
        //POST - JSON 設置取消任務標籤
        mCallHashMap.put(tag,call);
        //POST - JSON 發起請求
        call.enqueue(callback);
    }
    /**
     * 移除 取消網絡任務
     *
     * @param tag
     */
    public void removeRequest(String tag) {
        //獲取KEY的集合
        Set<Map.Entry<String, Call>> keyEntries = mCallHashMap.entrySet();
        //若是包含KEY
        if (keyEntries.contains(tag)) {
            //獲取對應的Call
            Call call = mCallHashMap.get(tag);
            //若是沒有被取消 執行取消的方法
            if (!call.isCanceled()) {
                call.cancel();
            }
            //移除對應的KEY
            mCallHashMap.remove(tag);
        }
    }

在這裏,咱們將參數以map集合形式傳入,而後封裝成JSONObject對象,而後在構造請求體,

例 :

private void postJsonFunction() {
        //請求連接
        String url = "http://192.168.1.107:8080/OkhttpAppLication/test";
        //網絡請求標識
        String tag = "getRequest";

        //提交參數
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("userName", "xxx");
        paramMap.put("password", "123456");
        paramMap.put("sex", "man");


        //添加請求Header
        Map<String, String> heardMap = new HashMap<>();
        heardMap.put("verson", "11");
        CommonOkhttpUtils.getUtilsInstance().okPostJSONRequest(url, heardMap, paramMap, CacheControl.FORCE_NETWORK, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請求失敗回調方法
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請求成功回調方法
            }
        }, tag);
    }

經過抓包工具能夠看到提交的請求數據爲:

請求方式爲:

八、POST異步請求提交JSON數據

/**
     * 異步POST網絡請求 提交JSON數據
     *
     * @param url          請求網絡連接
     * @param headerMap    請求網絡添加頭信息
     * @param JSONBody     請求網絡JSON字符串
     * @param cacheControl 緩存模式
     *                     
     *                     public static final CacheControl FORCE_NETWORK = ..;
     *                    
     *                     public static final CacheControl FORCE_CACHE = ...
     * @param callback     響應回調
     * @param tag          網絡任務標識
     */
    public void okPostJSONRequest(String url, Map<String, String> headerMap, String JSONBody, CacheControl cacheControl, Callback callback, String tag) {
        //獲取Builder
        Request.Builder builder = new Request.Builder().url(url);
        // 設置緩存
        if (cacheControl != null) {
            builder.cacheControl(cacheControl);
        }

        //添加請求頭信息
        if (headerMap != null && !headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        //獲取RequestBody
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONBody);
        //獲取 Request
        Request request = builder.post(requestBody).build();
        //獲取Call
        Call call = mOkHttpClient.newCall(request);
        //POST - JSON 設置取消任務標籤
        mCallHashMap.put(tag, call);
        //POST - JSON 發起請求
        call.enqueue(callback);
    }

在這裏,咱們將直接構造好的JSON 字符串直接傳入到方法中,而後構造請求體

案例:

private void postJsonFunction1() {
        //請求連接
        String url = "http://192.168.1.107:8080/OkhttpAppLication/test";
        //網絡請求標識
        String tag = "getRequest";

        //提交參數
       String JSONString = "";

        JSONObject jsonObj = new JSONObject();
        JSONArray jsonArray = new JSONArray();
        try {
            for (int i = 0; i < 4; i++) {
                JSONObject jsono = new JSONObject();
                jsono.put("userName", "xxx" + i);
                jsono.put("password", "123456" + i);
                jsonArray.put(jsono);
            }
            jsonObj.put("date", jsonArray);
            jsonObj.put("sex", "man");
        }catch (Exception e){

        }
        JSONString = jsonObj.toString();

        //添加請求Header
        Map<String, String> heardMap = new HashMap<>();
        heardMap.put("verson", "11");
        CommonOkhttpUtils.getUtilsInstance().okPostJSONRequest(url, heardMap,JSONString, CacheControl.FORCE_NETWORK, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請求失敗回調方法
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請求成功回調方法
            }
        }, tag);
    }

提交的請求數據爲:

{
	"date": 
    [{
		"userName": "xxx0",
		"password": "1234560"
	}, {
		"userName": "xxx1",
		"password": "1234561"
	}, {
		"userName": "xxx2",
		"password": "1234562"
	}, {
		"userName": "xxx3",
		"password": "1234563"
	}],
	"sex": "man"
}

也就是說在這裏咱們能夠定義任意結構層次的JSON數據

九、POST異步請求提交String 數據

/**
     * 異步POST網絡請求 提交String數據
     *
     * @param url          請求網絡連接
     * @param headerMap    請求網絡添加頭信息
     * @param string   請求網絡JSON字符串
     * @param cacheControl 緩存模式
     *
     *                     public static final CacheControl FORCE_NETWORK = ..;
     *
     *                     public static final CacheControl FORCE_CACHE = ...
     * @param callback     響應回調
     * @param tag          網絡任務標識
     */
    public void okPostStringRequest(String url, Map<String, String> headerMap, String string, CacheControl cacheControl, Callback callback, String tag) {
        //獲取Builder
        Request.Builder builder = new Request.Builder().url(url);
        // 設置緩存
        if (cacheControl != null) {
            builder.cacheControl(cacheControl);
        }
        //添加請求頭信息
        if (headerMap != null && !headerMap.isEmpty()) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
        //獲取RequestBody
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/x-markdown; charset=utf-8"), string);
        //獲取 Request
        Request request = builder.post(requestBody).build();
        //獲取Call
        Call call = mOkHttpClient.newCall(request);
        //POST - JSON 設置取消任務標籤
        mCallHashMap.put(tag, call);
        //POST - JSON 發起請求
        call.enqueue(callback);
    }

案例:

private void postStringFunction() {
        //請求連接
        String url = "http://192.168.1.107:8080/OkhttpAppLication/test";
        //網絡請求標識
        String tag = "getRequest";

        //提交參數
       String str = "this is String request data";
        //添加請求Header
        Map<String, String> heardMap = new HashMap<>();
        heardMap.put("verson", "11");
        CommonOkhttpUtils.getUtilsInstance().okPostStringRequest(url, heardMap, str, CacheControl.FORCE_NETWORK, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                //請求失敗回調方法
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //請求成功回調方法
            }
        }, tag);
    }

提交的數據格式 :

提交的數據原型:

 

 

十、POST源碼簡述:

相關文章
相關標籤/搜索