简介: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使用完全教程。
每天多努力那么一点点,积少成多
网友评论