文章目录
OkHttp
一、简介
OkHttp是一款优秀的网络请求框架,针对于传输层的一种封装,基于socket通信
OkHttp有2.0版本和3.0的版本,目前常用的是OkHttp3
二、使用
1.引入库
编辑app/build.gradle文件在dependencies闭包中添加如下内容:
implementation 'com.squareup.okhttp3:okhttp:4.4.0'
2.同步post请求
代码如下:
// 实例化OkHttpClient对象
OkHttpClient client = new OkHttpClient();
//实例化RequestBody对象
RequestBody requestBody = new FormBody.Builder()
.add("", "")
.build();
// 实例化Request对象
Request request = new Request.Builder()
.url("www.baidu.com")
.post(requestBody)
.build();
try {
// Response对象存储的就是获取的数据
Response response = client.newCall(request).execute();
String data = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
3.异步post请求
代码如下:
//异步请求
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("", "")
.build();
Request request = new Request.Builder()
.url("www.baidu.com")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String responseData = response.body().string();
setUI(responseData);
}
});
4.封装OkHttp框架
OkHttpModel.java:
public class OkHttpModel {
private static final String TAG = "OkHttpModel";
private Context context;
private OkHttpClient mOkHttpClient;
public OkHttpModel(Context context){
this.context = context;
this.mOkHttpClient = new OkHttpClient();
}
public <T> void get(String url, Map<String, Object> params, ICallBack iCallBack) {
final Request request = new Request.Builder()
.url(url)
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
iCallBack.onFailed(e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String result = response.body().string();
Log.d(TAG, "run: " + result);
iCallBack.onSuccess(result);
}
}
});
}
public <T> void post(String url, Map<String, Object> params, ICallBack iCallBack) {
FormBody.Builder bodyBuilder = new FormBody.Builder();
for (String key : params.keySet()) {
bodyBuilder.add(key, (String)params.get(key));
}
final Request request = new Request.Builder()
.url(url)
.post(bodyBuilder.build())
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
iCallBack.onFailed(e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String result = response.body().string();
Log.d(TAG, "run: " + result);
iCallBack.onSuccess(result);
}
}
});
}
}
ICallBack.java
public interface ICallBack<T> {
void onSuccess(T response);
void onFailed(String failed);
}
三、源码解析
1.请求流程
RealCall.java:
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
client.dispatcher().finished(this);
}
}
//判断是否重复请求
synchronized void setForWebSocket() {
if (executed) throw new IllegalStateException("Already Executed");
this.retryAndFollowUpInterceptor.setForWebSocket(true);
}
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
AsyncCall.java (RealCall的内部类)
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl().toString());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException e) {
if (signalledCallback) {
// Do not signal the callback twice!
Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
总结:okHttpClient Request—>newCall—>RealCall.enqueue()—>判断是否重复请求—>dispatcher.enqueue()—>运行队列中请求数小于64,并且访问同一机器目标Host请求数小于5,直接加入到运行队列,否则加入到等待队列—>运行队列中,调用AsyncCall的excute方法直接运行—>通过责任链获取请求响应
2.构建者模式和责任链模式在OkHttp中应用
- 构建者模式创建对象:使用多个简单对象构成复杂对象,(Builder类,独立于其他对象),当内部数据过于复杂时,可以方便的构建出想要的对象,不用传递所有参数,但有代码冗余
Request request = new Request.Builder()
.url(url)
.build();
- 责任链模式处理网络请求:分级处理
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
//自定义拦截器(可自己添加处理)
interceptors.addAll(client.interceptors());
//重试重定向拦截器
interceptors.add(retryAndFollowUpInterceptor);
//桥拦截器(添加Header,gzip)
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//缓存拦截器(减少重复的网络请求,通过时间判断)
interceptors.add(new CacheInterceptor(client.internalCache()));
//连接拦截器(在连接池中拿socket对象)
interceptors.add(new ConnectInterceptor(client));
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
//网络请求拦截器(可以观察到所有通过网络传输的数据)
interceptors.addAll(client.networkInterceptors());
}
//callServer拦截器(数据交互)
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
总结:自定义拦截器(可自己添加处理)—>重试重定向拦截器—>桥拦截器(添加Header,gzip)—>缓存拦截器(减少重复的网络请求,通过时间判断)—>连接拦截器(在连接池中拿socket对象)—>网络请求拦截器(可以观察到所有通过网络传输的数据)—>callServer拦截器(数据交互)
- 添加自定义拦截器
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor())
.build();
3.OkHttp对网络请求做了哪些优化
- 缓存拦截器
- 桥拦截器
4.怎么设计一个网络请求框架
- 参考现有框架
- 考虑扩展,优化(Https)
5.OkHttp2和OkHttp3的区别
1、包名改变
包名改了由之前的com.squareup.http改为 okhttp3
2、OkHttpClient参数配置(构建者模式)
之前参数可以直接mOkHttpClient.setCache(cache)设置,现在OkHttpClient使用构建者模式,需要在OkHttpClient.Builder上设置可配置