美文网首页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 二次封装网络框架

    简介:OKHttp是一个Android当前最火的处理网络请求第三方框架库,由移动支付Square公司开源贡献的。用...

  • Retrofit2的分享

    Retrofit2是一个网络框架,基于OkHttp3框架封装的网络框架。 大致理解,实现一个Api对应的接口,调用...

  • Retrofit2(2.4.0)

    对okhttp3进行封装的网络框架github 1. 该框架用到的东西 该框架用了大量的注解该框架依赖于okhtt...

  • 2019-11-07

    网络模块初步了解 内部使用的网络框架是OKHTTP3 将OkHttpClient的各自操作封装成一个类“HttpC...

  • OkHttp3源码分析

    OkHttp3是目前Android热门的网络请求框架之一,本篇来分析一下OkHttp3最主要的几部分: 同步、异步...

  • Android 二次封装网络加载框架

    Android 二次封装网络加载框架 写在最前面 开发当中,在请求网络的时候,大家或多或少都会使用一些第三方框架,...

  • Android网络框架二次封装

    我来了我来了,今天手把手教你二次封装网络框架 首先为什么需要二次封装网络框架? 情景一 领导说,小明咱们需要有个网...

  • RestAndroidHttp

    RestAndroidHttp 基于okhttp3 简单封装的一个网络请求框架。 用法 直接下载源码集成到自己的工...

  • kotlin下使用Retrofit进行网络请求以及Cookies

    之前刚接触Android时用OkHttp3来进行网络请求的,这次换成了基于OkHttp封装的Retrofit,两者...

  • Android Retrofit2 源码分析(一)—— Retr

    Retrofit2 简介 做为当前 Android 最主流的网络框架(我个人认为)。 它基于 OkHttp3(sq...

网友评论

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

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