上一篇介绍了OkHttp的基本使用。本篇介绍OkHttp的封装思路并进行简单封装。
一、为什么要进行封装?
1、在实际开发中,我们有很多的业务模块,每一个业务模块都具有相应的网络请求。
2、如果每一个业务模块都依赖具体的网络实现,随着技术的发展,当有更好的网络请求框架出现时,如果对现有项目网络部分的重构的时候,会发现是一件非常麻烦的事情。
3、归根结底,就是扩展性较差。
二、思路
在计算机领域当中,没有什么是增加一层解决不了的。所以我们通过增加一层的方式来增加代码的扩展性。通过分层的思想来对网络框架进行封装。
三、解决办法
1、业务模块实现层不依赖具体的网络库实现。而是依赖网络库的抽象层。
2、抽象层定义的是http的请求过程,所以基本不会发生变动。
okhttp封装思路.png
如果对网络框架进行优化的时候,只需要修改框架的实现层即可。
四、封装
网络请求一般分为三步:
请求过程.png通过分层的思想将网络部分分为网络抽象层,网络实现层。
OkHttp封装图解.png
1、我们的网络抽象层是通过接口定义。
2、根据请求过程将接口定义为IRequest,IHttpClient,IResponse
3、IHttpClient持有IRequest的依赖,携带请求信息。
4、BaseRequest,BaseResponse,HttpClentImpl为对应接口实现。
5、HttpCllientImpl的具体请求是通过OkHttp3来完成。
一、接口抽象层
1、IRequest
/**
* Created by wen_wen on 2018/4/10.
* 请求数据封装方式
*/
public interface IRequest {
String POST = "POST";
String GET = "GET";
/**
* 请求方式
*
* @param method
*/
void setMethod(String method);
/**
* 请求头
*
* @param key
* @param value
*/
void setHeader(String key, String value);
/**
* 请求体
*
* @param key
* @param value
*/
void setBody(String key, String value);
/**
* 执行URL
*
* @return
*/
String getUrl();
/**
*获取请求头部
*/
Map<String,String> getHeader();
/**
* 提供执行库请求参数
*/
Object getBody();
}
2、IResponse
/**
* Created by wen_wen on 2018/4/10.
* 接收网络实现层的返回结果
*/
public interface IResponse {
/**
* 状态码
* @return
*/
int getCode();
/**
* 数据
*/
String getData();
}
3、IHttpClient
/**
* Created by wen_wen on 2018/4/10.
* 请求方式
*/
public interface IHttpClient {
/**
* 持有IRequest的依赖 ,是否使用缓存(可配置)
* @param request
* @param froceCache
*/
IResponse get(IRequest request, boolean froceCache);
IResponse post(IRequest request, boolean forceCache);
}
二、实现层
1、BaseRequest
/**
* Created by wen_wen on 2018/4/10.
*/
public class BaseRequest implements IRequest {
//默认请求POST方式
private String method = POST;
private String url;
private Map<String, String> header;
private Map<String, String> body;
public BaseRequest(String url) {
//初始化公共参数 例如:公共的头部信息
this.url = url;
header = new HashMap<>();
body = new HashMap<>();
}
@Override
public void setMethod(String method) {
this.method = method;
}
@Override
public void setHeader(String key, String value) {
header.put(key, value);
}
@Override
public void setBody(String key, String value) {
body.put(key, value);
}
@Override
public String getUrl() {
//可配置 ,是具体不同的url做不同的转换
return url;
}
@Override
public Map<String, String> getHeader() {
return header;
}
@Override
public Object getBody() {
if (body != null) {
return new Gson().toJson(body, HashMap.class);
} else {
return "{}";//可配置
}
}
}
2、BaseResponse
/**
* Created by wen_wen on 2018/4/10.
*/
public class BaseResponse implements IResponse {
//响应码
private int code;
//响应数据
private String data;
public void setCode(int code) {
this.code = code;
}
public void setData(String data) {
this.data = data;
}
@Override
public int getCode() {
return code;
}
@Override
public String getData() {
return data;
}
}
3、OkHttpClientImpl
/**
* Created by wen_wen on 2018/4/10.
* okhttp实现 持有okhttp3的实例,并进行具体的网络请求
*/
public class OkHttpClientImpl implements IHttpClient {
OkHttpClient client = new OkHttpClient.Builder()
.build();
/**
* get请求
*
* @param request
* @param froceCache
*/
@Override
public IResponse get(IRequest request, boolean froceCache) {
/**
* 解析参数 从BaseRequest,转化为OkHttp3需要的业务参数
*/
request.setMethod(IRequest.GET);
Map<String, String> header = request.getHeader();
//创建Builder
Request.Builder builder = new Request.Builder();
for (String key : header.keySet()) {
builder.header(key, header.get(key));//将设置的header信息,设置到Okhttp3的header中
}
//添加Url
builder.url(request.getUrl());
//构建Request
Request okRequest = builder.build();
return execute(okRequest);
}
@Override
public IResponse post(IRequest request, boolean forceCache) {
/**
* 请求类型 在上一篇文章中说明过
*/
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.create(mediaType, request.getBody().toString());
/**
* 解析业务参数
*/
request.setMethod(IRequest.POST);
Request.Builder builder = new Request.Builder();
Map<String, String> header = request.getHeader();
for (String key : header.keySet()) {
builder.header(key, header.get(key));
}
Request okRequest = builder.url(request.getUrl())
.post(body)
.build();
return execute(okRequest);
}
/**
* 具体的执行过程
* 注意:使用的同步请求
*/
private IResponse execute(Request request) {
BaseResponse baseResponse = new BaseResponse();
Response response = null;
try {
response = client.newCall(request).execute();
//设置状态码
baseResponse.setCode(response.code());
//设置返回数据
baseResponse.setData(response.body().string());
} catch (IOException e) {
e.printStackTrace();
//异常信息 自定义一个异常信息(可配置)
baseResponse.setCode(baseResponse.UNKNOW_ERROR);
baseResponse.setData(response.message());
}
return baseResponse;
}
}
4、测试
我们简单测试一下分装的网络请求库:
public class TestOkHttp3 {
@Test
public void testOkHttp3() {
final OkHttpClientImpl httpClient = new OkHttpClientImpl();
final IRequest request = new BaseRequest("https://github.com/");
IResponse response = httpClient.get(request, false);
System.out.println("响应数据:" + response.getData());
}
}
结果:
响应结果.png
五、结语
本文简单的对OkHttp3进行了大致的框架分装。其中很多的实现细节并没有实现,例如缓存的使用,重定向的使用。这些都是根据项目实际的业务需求来实现的。在后面的系列中,将会重新对封装的框架进行完善。
大家有什么问题欢迎留言。
网友评论