Android OKHttp3 二次封装网络框架

简介: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使用完全教程

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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一.网络通信概念理解 1.http协议概述 当我们在自己电脑的web浏览器地址栏敲入网址url,点击enter,...
    铜雀春深锁不住阅读 10,403评论 0 3
  • 一幢老旧的欧美式别墅屹立在坚实的围墙里,围墙的门是生了锈了的,打开围墙大门映入眼帘的是别墅的拱形大门。别墅的外墙长...
    小美2016阅读 4,206评论 2 3
  • 最近时间总是过得好快,生物钟也是乱的一塌糊涂,上午在睡觉,中午在摸家务,下午在陪儿子,晚上在看书,深更半夜在码字打...
    小米粥里的一条虫阅读 1,118评论 0 0
  • 2019年以来,鹊启平台坚持“不做第一,只做唯一”的企业愿景,秉承“大平台、大市场、大环境、大客户”的经营...
    说说室内装饰阅读 1,781评论 0 0
  • 不知不觉又到10点了,一会儿要睡觉了。 一天又过去了。 当然我也没那么在意一天,他就像匆匆走过的一步。 总期待空闲...
    部落10阅读 4,241评论 0 0