美文网首页Android
Android OKHttp3 二次封装网络框架

Android OKHttp3 二次封装网络框架

作者: 极客匠 | 来源:发表于2020-02-26 23:30 被阅读0次

    简介:OKHttp是一个Android当前最火的处理网络请求第三方框架库,由移动支付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);
                    }
                }
            });
        }
    

    这种封装成工具类的比完全没有封装的好了很多,但是还是存在一定的问题的。封装成工具类的话,别人完全有权限访问你这个工具类,他可以随时修改你工具类里面的实现,这给维护带来了一定的成本。

    再此之前,我们要先了解网络请求哪些参数是必要的,哪些是非必要的

    • 必要选项
      • url,请求地址
      • paramMap,请求参数
      • IResponseCallback,请求结果回调
    • 非必要选项
      • context 通常是用来配置配置一些缓存等一些信息
      • headMap 请求头
      • tag 请求 TAG,用来区分或者取消网络请求
      • connectTimeout 连接超时时间
      • readTimeout 读取超时时间
      • writeTimeout 写入超时时间

    了解完必要参数和非必要参数之后,我们就将采用建造者模式,把非必要的参数都提取封装在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;
            }
        }
    
    }
    

    建造者模式的优点:

    - 封装性很好,将产品本身与产品的创建过程解耦,对外屏蔽了对象的构建过程
    - 扩展性强,如果有新的需求,只需要增加新的具体建造者,无须修改原有类库的代码
    

    这样封装实现出来的接口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 方法,主要用来配置一些初始化参数
    • doGet 有两个方法,其中一个方法是另外一个方法的重载,这样设计的目的是为了减少调用方法的时候减少方法参数的传递
    • doPost 跟 doGet 方法一样,就不说了
    • cancel 主要是用来取消网络请求的。在项目当中,在 Activity 或者 Fragment 销毁的时候,最好取消网络请求,不然可能导致内存泄露或者异常,如空指针异常等。

    ManbaOkhttpRequest实现

    OkHttp 的配置是非常灵活的,这样我们主要看一下怎么配置请求头,请求参数,以及怎样取消网络请求。

    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的实现其实很简单,主要根据ManbaOkhttpOption做相应的配置。如果不熟悉okhttp的request用法,请参考博客OkHttp使用完全教程

    每天多努力那么一点点,积少成多

    相关文章

      网友评论

        本文标题:Android OKHttp3 二次封装网络框架

        本文链接:https://www.haomeiwen.com/subject/lucnchtx.html