Android OKHttp3 二次封裝網(wǎng)絡(luò)框架

簡介:OKHttp是一個Android當前最火的處理網(wǎng)絡(luò)請求第三方框架庫,由移動支付Square公司開源貢獻的。用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)。

封裝

  • 對第三方框架進行封裝,是為了達到對模塊項目的控制,已最小的代價替換框架,達到對項目的控制。

首先看一下OKHttp的使用

private static OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS)
               .readTimeout(30, TimeUnit.SECONDS)
               .addInterceptor(new LoggingInterceptor())
               .cache(new Cache(context.getExternalFilesDir("okhttp"),cacheSize)).build();


    public static void getRequest(String url, final ResultListener<Object> listener) {
        Request request = new Request.Builder().url(url).method("GET", null).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                if (null != listener) {
                    listener.onFailure(e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (null != listener) {
                    listener.onSuccess(response);
                }
            }
        });
    }

這種封裝成工具類的比完全沒有封裝的好了很多,但是還是存在一定的問題的。封裝成工具類的話,別人完全有權(quán)限訪問你這個工具類,他可以隨時修改你工具類里面的實現(xiàn),這給維護帶來了一定的成本。

再此之前,我們要先了解網(wǎng)絡(luò)請求哪些參數(shù)是必要的,哪些是非必要的

  • 必要選項
    • url,請求地址
    • paramMap,請求參數(shù)
    • IResponseCallback,請求結(jié)果回調(diào)
  • 非必要選項
    • context 通常是用來配置配置一些緩存等一些信息
    • headMap 請求頭
    • tag 請求 TAG,用來區(qū)分或者取消網(wǎng)絡(luò)請求
    • connectTimeout 連接超時時間
    • readTimeout 讀取超時時間
    • writeTimeout 寫入超時時間

了解完必要參數(shù)和非必要參數(shù)之后,我們就將采用建造者模式,把非必要的參數(shù)都提取封裝在ManbaOkhttpOption當中。代碼如下:

public class ManbaOkhttpOption {
    private String mUrl;
    private String mTag;
    private Map<String, String> mHeaders;

    public ManbaOkhttpOption(String mTag) {
        this.mTag = mTag;
    }

    public String getTag() {
        return mTag;
    }

    public Map<String, String> getHeaders() {
        return mHeaders;
    }

    public static final class Builder {
        public String mTag;
        public Map<String, String> mHeaders;
        public String mUrl;

        public Builder setTag(String mTag) {
            this.mTag = mTag;
            return this;
        }

        public Builder setHeaders(Map<String, String> mHeaders) {
            this.mHeaders = mHeaders;
            return this;
        }

        public Builder setUrl(String mUrl) {
            this.mUrl = mUrl;
            return this;
        }

        public ManbaOkhttpOption build() {
            ManbaOkhttpOption option = new ManbaOkhttpOption(mTag);
            option.mHeaders = mHeaders;
            option.mUrl = mUrl;
            return option;
        }
    }

}

建造者模式的優(yōu)點:

- 封裝性很好,將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,對外屏蔽了對象的構(gòu)建過程
- 擴展性強,如果有新的需求,只需要增加新的具體建造者,無須修改原有類庫的代碼

這樣封裝實現(xiàn)出來的接口IManbaRequest:

public interface IManbaRequest {
    void init(Context context);

    void doGet(String url, IResponseCallback callback);

    void doGet(String url, Map<String, String> paramsMap, IResponseCallback callback);

    void doGet(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, IResponseCallback callback);

    void doPost(String url, Map<String, String> paramsMap, IResponseCallback callback);

    void doPost(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, IResponseCallback callback);

    void cancel(String tag);
}

可以看到,我們有幾個方法:

  • init 方法,主要用來配置一些初始化參數(shù)
  • doGet 有兩個方法,其中一個方法是另外一個方法的重載,這樣設(shè)計的目的是為了減少調(diào)用方法的時候減少方法參數(shù)的傳遞
  • doPost 跟 doGet 方法一樣,就不說了
  • cancel 主要是用來取消網(wǎng)絡(luò)請求的。在項目當中,在 Activity 或者 Fragment 銷毀的時候,最好取消網(wǎng)絡(luò)請求,不然可能導致內(nèi)存泄露或者異常,如空指針異常等。

ManbaOkhttpRequest實現(xiàn)

OkHttp 的配置是非常靈活的,這樣我們主要看一下怎么配置請求頭,請求參數(shù),以及怎樣取消網(wǎng)絡(luò)請求。

package com.sunhdj.manbaokhttp;

import android.content.Context;
import android.os.Handler;

import com.sunhdj.manbaokhttp.utils.NetUtils;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * huangdaju
 * 2020-02-25
 **/

public class ManbaOkhttpRequest implements IManbaRequest {

    private static int cacheSize = 10 * 1024 * 1024; // 10 MiB

    private static OkHttpClient client;
    private Context mContext;

    public static Handler mHandler = new Handler();

    public static Handler getHandler() {
        if (mHandler == null) {
            mHandler = new Handler();
        }
        return mHandler;
    }

    private volatile static ManbaOkhttpRequest instance = null;

    private ManbaOkhttpRequest() {
    }


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

    @Override
    public void init(Context context) {
        mContext = context.getApplicationContext();
        client = getCilent();
    }

    private OkHttpClient getCilent() {
        if (client == null) {
            OkHttpClient.Builder mBuilder = new OkHttpClient.Builder().
                    connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .addInterceptor(new LoggingInterceptor())
                    .cache(new Cache(mContext.getExternalFilesDir("manbaOkhttp"), cacheSize));
            client = mBuilder.build();
        }
        return client;

    }

    @Override
    public void doGet(String url, IResponseCallback callback) {
        doGet(url, null, null, callback);
    }

    @Override
    public void doGet(String url, Map<String, String> paramsMap, IResponseCallback callback) {
        doGet(url, paramsMap, null, callback);
    }

    @Override
    public void doGet(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, final IResponseCallback callback) {

        url = NetUtils.appendUrl(url, paramsMap);
        final ManbaOkhttpOption manbaOkhttpOption = NetUtils.checkNetworkOption(option, url);
        Request.Builder builder = new Request.Builder().url(url).tag(manbaOkhttpOption.getTag());
        builder = configHeaders(builder, manbaOkhttpOption);

        Request build = builder.build();

        getCilent().newCall(build).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e, callback);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response, callback);
            }
        });
    }

    @Override
    public void doPost(String url, Map<String, String> paramsMap, IResponseCallback callback) {
        doPost(url,paramsMap,null,callback);
    }

    @Override
    public void doPost(String url, Map<String, String> paramsMap, ManbaOkhttpOption option, final IResponseCallback callback) {
        url = NetUtils.appendUrl(url, paramsMap);
        final ManbaOkhttpOption manbaOkhttpOption = NetUtils.checkNetworkOption(option, url);
        // 以表單的形式提交
        FormBody.Builder builder = new FormBody.Builder();
        builder=configPostParam(builder,paramsMap);
        FormBody formBody = builder.build();

        Request.Builder requestBuilder = new Request.Builder().url(url).post(formBody).tag(manbaOkhttpOption.getTag());
        requestBuilder = configHeaders(requestBuilder, manbaOkhttpOption);

        Request build = requestBuilder.build();

        getCilent().newCall(build).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handleError(e, callback);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                handleResult(response, callback);
            }
        });
    }

    private FormBody.Builder configPostParam(FormBody.Builder builder, Map<String, String> paramsMap) {
        if(paramsMap!=null){
            Set<Map.Entry<String, String>> entries = paramsMap.entrySet();
            for(Map.Entry<String,String> entry:entries ){
                String key = entry.getKey();
                String value = entry.getValue();
                builder.add(key,value);
            }
        }
        return builder;
    }

    private Request.Builder configHeaders(Request.Builder builder, ManbaOkhttpOption option) {
        Map<String, String> headers = option.getHeaders();
        if (headers == null || headers.size() == 0) {
            return builder;
        }
        Set<Map.Entry<String, String>> entries = headers.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            builder.addHeader(key, value);
        }
        return builder;

    }


    private void handleResult(Response response, final IResponseCallback callback) throws IOException {
        final String result = response.body().string();
        if (callback != null) {
            getHandler().post(new Runnable() {
                @Override
                public void run() {
                    callback.onResponse(result);
                }
            });
        }
    }

    private void handleError(IOException e, final IResponseCallback callback) {
        if (callback != null) {
            final ManbaOkHttpException httpException = new ManbaOkHttpException();
            httpException.e = e;
            getHandler().post(new Runnable() {
                @Override
                public void run() {
                    callback.onFail(httpException);
                }
            });

        }
    }

    @Override
    public void cancel(String tag) {
        if (client != null) {
            for (Call call : client.dispatcher().queuedCalls()) {
                if (call.request().tag().equals(tag)) {
                    call.cancel();
                }
            }
        }
    }
}

ManbaOkhttpRequest的實現(xiàn)其實很簡單,主要根據(jù)ManbaOkhttpOption做相應(yīng)的配置。如果不熟悉okhttp的request用法,請參考博客OkHttp使用完全教程

每天多努力那么一點點,積少成多

?著作權(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)容

  • 一.網(wǎng)絡(luò)通信概念理解 1.http協(xié)議概述 當我們在自己電腦的web瀏覽器地址欄敲入網(wǎng)址url,點擊enter,...
    銅雀春深鎖不住閱讀 5,114評論 0 3
  • 一幢老舊的歐美式別墅屹立在堅實的圍墻里,圍墻的門是生了銹了的,打開圍墻大門映入眼簾的是別墅的拱形大門。別墅的外墻長...
    小美2016閱讀 880評論 2 3
  • 最近時間總是過得好快,生物鐘也是亂的一塌糊涂,上午在睡覺,中午在摸家務(wù),下午在陪兒子,晚上在看書,深更半夜在碼字打...
    小米粥里的一條蟲閱讀 188評論 0 0
  • 2019年以來,鵲啟平臺堅持“不做第一,只做唯一”的企業(yè)愿景,秉承“大平臺、大市場、大環(huán)境、大客戶”的經(jīng)營...
    說說室內(nèi)裝飾閱讀 301評論 0 0
  • 不知不覺又到10點了,一會兒要睡覺了。 一天又過去了。 當然我也沒那么在意一天,他就像匆匆走過的一步。 總期待空閑...
    部落10閱讀 887評論 0 0

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