关于OKhttp二次封装的理解和分析

原封装地址为鸿神的Android 一个改善的okHttp封装库。以下是自我总结和理解,不自己写一遍实在理解不了 - -!写完后扔掉又太可惜了,so.....

OkHttp的基本请求

  1. 创建OkHttpClient对象

    OkHttpClient client = new OkHttpClient();
  2. 构造RequestBody

    RequestBody body = new ReuqestBody();
  3. 构造Request

    Request request = new Request.Builder().url("").tag("").build();
  4. 创建Call对象,将Request加入Call对象中

    Call call = client.newCall(request);
  5. 将Call对象加入调度,并提供回调函数

    call.enqueue(new CallBack());

重点区别在于RequestBody创建方式的不同。我们希望对着5个步骤进行封装,

  1. 封装OkHttpClient对象,我们提供一个单例总类(OkHttpManager)进行控制,创建OkHttpClient并提供UI线程方法。
  2. 抽象出RequestBody对象,因为RequestBody对象以来Request对象,所以优先考虑Request对象的构建。
  3. 封装Request对象,提供类(OkHttpRequest)进行控制,分别提供url,tag,params,headers接口,对数据进行绑定,然后提供build方法用来获取Request对象;因为RequestBody构建方式的不同,所以提供抽象方法buildRequestBody构建RequestBody,提供buildRequest抽象方法构建Request请求,最后通过build方法返回Request对象。
  4. 封装RequestCall方法,因为Call方法需要传入Request对象,所以RequestCall包含OkHttpRequest对象,所以提供方法buildCall方法构造Call对象,同时传递参数CallBack进行回调函数设定;通过OkHttpManager获取OkHttpClient对象并在buildCall方法中将Call对象加入调度。
  5. 我们希望CallBack方法也可以进行自定义,所以自行创建回调泛型类(CallBack),创建基本网络访问方法,如onBefore、inProcess、onAfter;onSuccess、onFailure。提供parseNetworkResponse方法返回数据解析类型。创建DEFAULT_CALLBACK静态变量提供默认的CallBack实现。

以上步骤基本封装完成,接下来分析细节实现。



OkHttpManager类

我们希望此类中可以进行总体的管理
希望对请求时间,超时时间等进行默认限制,所以定义字段DEFAULT_MILLISECONDS;
希望此类可以封装UI线程,这样可以避免编写大量的Hndaler通信,所以定义变量mDelivery实现主线程的UI通信;
同时封装变量mOkHttpClient,并封装OkHttpManager本身,采用单例模式提供getInstance方法获取实例;
我们在构造函数中进行mDelivery、mOkHttpClient变量的初始化工作。对应步骤1,代码如下:

private OkHttpManager(OkHttpClient okHttpClient) {
    if (okHttpClient == null) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        //builder.cookieJar(null);
        //builder.hostnameVerifier(null);
        mOkHttpClient = builder.build();
        mDelivery = new Handler(Looper.getMainLooper());
    } else {
        mOkHttpClient = okHttpClient;
    }
}



OkHttpRequest类

Request封装类,创建变量Request、RequestBody。
作为Request封装类,应该具有Request请求构造中的基本变量,所以我们创建tag(标记请求),params(保存参数),header(请求头信息),url(请求链接)四个基本参数;并创建Request.Builder对象用来构造请求。

构造函数
我们在构造函数中进行四个基本变量的初始化操作,并进行参数校验,进而使用builder对象去构造基本对象请求

  1. 构造url
  2. 标记tag
  3. 构造请求头

对应步骤3 代码如下:

 public OkHttpRequest(String url, Object tag, Map<String, String> params, Map<String, String> headers) {
    this.mUrl = url;
    this.mTag = tag;
    this.params = params;
    this.mHeaders = headers;
    if (StringUtils.isNullOrEmpty(url)) {
        Exception.illegalArgument("url 不能为空");
    }
    initBuilder();
}

/**
 * 初始化Builder
 */
protected void initBuilder() {
    builder.url(mUrl).tag(mTag);
    appendHeaders();
}

/**
 * 构建请求头
 */
protected void appendHeaders() {
    Headers.Builder headerBuilder = new Headers.Builder();
    if (mHeaders == null || mHeaders.isEmpty()) {
        return;
    }
    builder.headers(headerBuilder.build());

    for (String key : mHeaders.keySet()) {
        headerBuilder.add(key, mHeaders.get(key));
    }
}

每个请求的不同之处在于参数的构造情况,所以我们创建抽象方法buildRequestBody进行参数构造(对应步骤2),创建抽象方法buildRequest构造请求,buildRequest需传入RequestBody变量
创建方法generateRequest,在内部进行Request的构造,代码如下:

 public Request generateRequest(CallBack callback) {
    RequestBody requestBody = buildRequestBody();
    RequestBody warpRequestBody = warpRequestBody(requestBody, callback);
    Request request = buildRequest(warpRequestBody);
    return request;
}



RequestCall类

对OkHttpRequest类的二次封装;因为是对OkHttpRequest类的封装,所以拥有变量mOkHttpRequest、mRequest和mCall;
创建方法generateRequest,通过OkHttpRequest.generateRequest拿到构造的Request
创建方法buildCall(对应步骤4),在此方法中构造Call,如果对超时、请求时间等有限制,则构造新的OkHttpClient,并将Call加入调度,对应步骤5
代码如下:

/**
 * 构造Call对象
 * @param callBack
 * @return
 */
public Call buildCall(CallBack callBack) {
    mRequest = generateRequest(callBack);
    if (connTimeOut > 0 || writeTimeOut > 0 || readTimeOut > 0) {
        connTimeOut = connTimeOut > 0 ? connTimeOut : OkHttpManager.DEFAULT_MILLISECONDS;
        writeTimeOut = writeTimeOut > 0 ? connTimeOut : OkHttpManager.DEFAULT_MILLISECONDS;
        readTimeOut = readTimeOut > 0 ? connTimeOut : OkHttpManager.DEFAULT_MILLISECONDS;
        clone = OkHttpManager.getInstance().getOkHttpClient().newBuilder()
                .connectTimeout(connTimeOut, TimeUnit.MILLISECONDS)
                .writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS)
                .readTimeout(readTimeOut, TimeUnit.MILLISECONDS)
                .build();
        mCall = clone.newCall(mRequest);
    } else {
        mCall = OkHttpManager.getInstance().getOkHttpClient().newCall(mRequest);
    }
    return mCall;
}

/**
 * 获取Request
 * @param callBack
 * @return
 */
private Request generateRequest(CallBack callBack) {
    return mOkHttpRequest.generateRequest(callBack);
}

提供excute方法进行调度方法,将调度的实现过程转移至OkHttpManager中

/**
 * 调度方法
 * @param callback
 */
public void excute(CallBack callback) {
    buildCall(callback);
    if (callback != null) {
        callback.onBefore(mRequest);
    }
    OkHttpManager.getInstance().excute(this, callback);
}

最终,我们在OkHttpManager类中添加调度方法,传入二次封装类RequestCall、CallBack两个参数。并通过RequestCall获取Call对象,然后进行调度。代码如下:

/**
 * 最终调度
 * @param requestCall
 * @param callback
 */
public void excute(final RequestCall requestCall, CallBack callback) {
    if (callback == null) {
        callback = CallBack.DEFAULT_CALLBACK;
    }
    final CallBack finalCallback = callback;
    requestCall.getCall().enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            sendFailResultCallback(call, e, finalCallback);
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.code() >= 400 && response.code() <= 599) {
                sendFailResultCallback(call, new RuntimeException(response.body().string()), finalCallback);
                return;
            }
            Object o = finalCallback.parseNetworkResponse(response);
            sendSuccessResultCallback(o, finalCallback);
        }
    });
}

/**
 * 成功回调
 * @param o
 * @param finalCallback
 */
private void sendSuccessResultCallback(final Object o, final CallBack finalCallback) {
    mDelivery.post(new Runnable() {
        @Override
        public void run() {
            finalCallback.onSuccess(o);
            finalCallback.onAfter();
        }
    });
}

/**
 * 失败回调
 * @param call
 * @param e
 * @param finalCallback
 */
private void sendFailResultCallback(final Call call, final Exception e, final CallBack finalCallback) {
    mDelivery.post(new Runnable() {
        @Override
        public void run() {
            finalCallback.onFailure(call, e);
            finalCallback.onAfter();
        }
    });
}

以上,所有步骤均已实现完毕。

使用时,例如我们希望创建一个通用post请求,则先创建PostRequest继承OkHttpRequest。重写方法biuldResponseBody即可,代码如下:

@Override
public RequestBody warpRequestBody(RequestBody requestBody, final CallBack callback) {
    if (callback == null) return requestBody;
    CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.Listener() {
        @Override
        public void onRequestProgress(final long bytesWritten, final long contentLength) {
            OkHttpManager.getInstance().getDelivery().post(new Runnable() {
                @Override
                public void run() {
                    callback.inProcess(bytesWritten * 1.0f / contentLength);
                }
            });
        }
    });
    return super.warpRequestBody(requestBody, callback);
}

@Override
protected Request buildRequest(RequestBody requestBody) {
    return builder.post(requestBody).build();
}

@Override
protected RequestBody buildRequestBody() {
    FormBody.Builder builder = new FormBody.Builder();
    addParams(builder);
    return builder.build();
}

在OkHttpManager类中添加方法post(url,tag...)等,返回RequestCall。

接下来,我们希望通过post.url(url)的方式进行参数构建,有利代码可读性。
首先,创建抽象OkHttpRequestBuilder类,类中增加抽象方法url、tag、header,参数的不确定性,提供hasParams接口进行参数绑定。最终提供build方法返回一个RequestCall对象进行最终调度。

所以在OkHttpManager类添加方法post,返回一个PostRequestBuilder类,重写build方法,将url等变量传递至PostRequest构造函数中,返回RequestCall对象。代码如下:

@Override
public RequestCall build() {
    return new PostFormRequest(url, tag, params, header).build();
}

最终的调用形式便成为

 OkHttpManager. post()                                  //获取RequestBilder抽象类
                    .addParams("username", "测试新框架") //设置参数
                    .addParams("password", "123456")    //设置参数
                    .url(UrlConfig.REGISTER)            //设置参数
                    .tag(this)                          //设置参数
                    .build()
                    .excute(new CallBack<String>() {    //调用RequestCall.excute方法,并传入回调函数
                        @Override
                        public String parseNetworkResponse(Response response) {
                            try {
                                return response.body().string();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            return null;
                        }

                        @Override
                        public void onSuccess(String response) {
                            ToastUtils.show(getActivity(), response, 1000);
                        }

                        @Override
                        public void onFailure(Call call, Exception e) {
                        }
                    });

完毕,以上是个人对封装的理解,有错误的地方请指出,原封装地址为鸿神的Android 一个改善的okHttp封装库。

你可能感兴趣的:(关于OKhttp二次封装的理解和分析)