okHttp网络请求
来源:互联网 发布:winner知乎 编辑:程序博客网 时间:2024/04/29 03:50
一,异步OkHttp请求示例
private void testOkHttp() throws IOException { final OkHttpClient client = new OkHttpClient(); final Request request = new Request.Builder().url("https://www.google.com.hk").build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Log.i(TAG,response.toString()); Log.i(TAG,response.body().string()); } }); }
上面的代码就实现了一个网络请求. 创建一个OkHttpClient对象,他包含了分发器,连接池,拦截器等等内容. 接下来创建一个请求对象,通过OkHttpClient的newCall()方法对其包装,然后添加请求队列,然后回调结果
Tip
对于OkHttpClient封装一个单实例,让所有的Http请求都重用它, OkHttp将会有更好的性能.因为每一个OkHttpClient实例都持有自己的连接池,线程池等,重用连接池和线程池能够减少网络访问延迟以及节省内存,减少资源的浪费
下面我们就详细的分析一下OkHttp详细的网络访问流程
二,OkHttp详访流程
1,创建HttpClient对象.
public OkHttpClient() { this(new Builder()); } OkHttpClient(Builder builder) { this.dispatcher = builder.dispatcher; this.proxy = builder.proxy; this.protocols = builder.protocols; this.connectionSpecs = builder.connectionSpecs; this.interceptors = Util.immutableList(builder.interceptors); this.networkInterceptors = Util.immutableList(builder.networkInterceptors); this.proxySelector = builder.proxySelector; this.cookieJar = builder.cookieJar; this.cache = builder.cache; this.internalCache = builder.internalCache; this.socketFactory = builder.socketFactory; ... ... this.proxyAuthenticator = builder.proxyAuthenticator; this.authenticator = builder.authenticator; this.connectionPool = builder.connectionPool; this.dns = builder.dns; this.followSslRedirects = builder.followSslRedirects; this.followRedirects = builder.followRedirects; this.retryOnConnectionFailure = builder.retryOnConnectionFailure; this.connectTimeout = builder.connectTimeout; this.readTimeout = builder.readTimeout; this.writeTimeout = builder.writeTimeout; this.pingInterval = builder.pingInterval; }
由上面可知HttpClient创建的时候,初始化了连接池,线程池,默认拦截器等等,为接下来的网络请求铺垫
2,创建Request对象
1)
Request request = new Request.Builder().url("https://www.google.com.hk").build();
通过Request中的Builder构建一个请求对象
这个Request对象我们可以理解成一个请求Bean,里面封装了请求的url, 请求方法(post get put delete等),请求头,请求体,以及tag(用于批量取消)
public Call newCall(Request request) { return new RealCall(this, request, false /* for web socket */); }
接下来继续对Request对象进行包装,使其能够执行execute,入队enqueue, 取消cancel, 判断状态 isCancel和isExecuted
上面的call指向的是RealCall对象
我们看下Call接口
public interface Call extends Cloneable { Request request(); Response execute() throws IOException; void enqueue(Callback responseCallback); void cancel(); boolean isExecuted(); boolean isCanceled(); Call clone(); interface Factory { Call newCall(Request request); }}
3,将请求入队
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
OkHttpClient的dispatcher()方法返回的是一个Dispatcher对象,每个Dispatcher使用线程池来运行上面的Call任务.
接下来我们看下Dispacher的入队操作
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
runningAsyncCalls存放所有正在执行的异步任务
readyAsyncCalls存放所有正在等待执行的异步任务
当正在执行的请求小于最大请求数64且每个主机的最大请求数不超过5 则直接加入到正在执行的异步队列中且执行.
否则加入到正在等待执行的异步队列中等待执行.
由上我们可知
请求相同主机的最大请求数目是5
所有请求最大数目是64
实际开发中,用户量一般的app服务器只有一个,那么一般最大的请求就是5
好了,一个请求封装准备了这么多, 顺利入队,下面我们看看他下面是怎么执行的
4,执行
RealCall封装了原始的Request,在RealCall中有一个非静态内部类AsyncCall,AsyncCall中的execute方法就是任务要执行的代码
final class AsyncCall extends NamedRunnable { ... ... ... ... @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); } } }
通过getResponseWithInterceptorChain方法 获取到Response对象,下面我们看下他的拦截链
Response getResponseWithInterceptorChain() throws IOException { // Build a full stack of interceptors. List<Interceptor> interceptors = new ArrayList<>(); interceptors.addAll(client.interceptors()); interceptors.add(retryAndFollowUpInterceptor); interceptors.add(new BridgeInterceptor(client.cookieJar())); interceptors.add(new CacheInterceptor(client.internalCache())); interceptors.add(new ConnectInterceptor(client)); if (!forWebSocket) { interceptors.addAll(client.networkInterceptors()); } interceptors.add(new CallServerInterceptor(forWebSocket)); Interceptor.Chain chain = new RealInterceptorChain( interceptors, null, null, null, 0, originalRequest); return chain.proceed(originalRequest); }RealInterceptorChain.javapublic Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, Connection connection) throws IOException { ... ... //取出下一个拦截器,递归调用 RealInterceptorChain next = new RealInterceptorChain( interceptors, streamAllocation, httpCodec, connection, index + 1, request); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); ... ... return response; }
1)首先添加用户自定义的拦截器(如果有),接着依次添加重试拦截器,桥接拦截器,缓存拦截器,连接拦截器以及访问服务器的拦截器.
这些拦截器的添加顺序是固定的,不能改变
2)这些拦截器形成一个拦截链,每个拦截器专司其自己的职责, 将处理好的请求交给下一个拦截器,最后一个拦截器处理完毕后,再将其交给上一个拦截器,直到第一个, 最后将结果返回.这样一个责任链就形成了
3)每个拦截器都实现Interceptor接口
public interface Interceptor { Response intercept(Chain chain) throws IOException; interface Chain { Request request(); Response proceed(Request request) throws IOException; Connection connection(); }}
4)对于拦截器之间的调用过程可能不太容易理解,下面针对2)给出一个示意图
Req: 请求Request缩写
Res: 响应Response缩写
5,结果回调
我们再将目光回到AsyncCall类
@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); } } }
当通过getResponseWithInterceptorChain()一系列的处理得到结果后.
1),会首先判断结果是否取消, 如果取消则回调传入的回调onFail中
否则,回调结果到onResponse中
2),接下来是扫尾操作
调用Dispatcher的finish方法
void finished(AsyncCall call) { finished(runningAsyncCalls, call, true); } private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) { int runningCallsCount; Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); if (promoteCalls) promoteCalls(); runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } }
它主要做了两件事儿
A,将刚才已经完成的任务从runningAsyncCalls移除
B,如果runningAsyncCall小于5(每个主机的最大访问数量), 则从readyAsyncCalls移除添加到runningAsyncCalls中,并且执行
至此一个完整的OkHttp异步请求完毕
总的来说: 就是根据请求的url, 请求方法, 请求体构造一个Request的Bean, 然后将Request封装成一个RealCall,RealCall实现了Call接口,他有对执行逻辑的操作(取消,执行,判断执行的状态等), 接下来通过全局的OkHttpClient(拥有线程池,连接池,分发器等资源),利用分发器Dispatcher加入到执行队列或者等待队列中.
然后线程池执行RealCall的非静态内部类AsyncCall的execute方法, 然后通过getResponseWithInterceptorChain来进行一系列的拦截器操作处理,回调请求结果.
最后进行扫尾操作,移除正在执行队列的当前请求,将等待队列的请求添加到执行队列.
OkHttp的处理核心是在拦截器,每个拦截器都有自己的职责,下一篇文章详细分析各个拦截器具体都干了什么
- java okhttp 网络请求
- OkHttp网络请求
- OKHttp请求网络数据
- okhttp网络请求框架
- 网络请求框架OKHttp
- OkHttp网络请求
- OkHttp网络请求框架
- OKHttp网络请求
- OkHttp 网络请求
- 网络请求okhttp框架
- OkHttp网络请求
- okHttp网络请求
- oKHttp网络请求
- OkHttp网络请求
- okHttp发起网络请求
- OkHttp网络数据请求
- OkHttp 网络请求
- okhttp网络请求简介
- ERROR Dispatcher Dispatcher initialization failed java.lang.RuntimeException: java.lang.RuntimeExc
- Sass的一点小用法
- zabbix告警信息-lykchat信息发送系统
- 104. Maximum Depth of Binary Tree
- Kubernetes 1.6 官方发布:支持多用户、多工作负载
- okHttp网络请求
- EasyDarwin开源流媒体服务器实现RTSP直播同步输出MP4、RTMP、HLS的方案思路
- char *指针与char 数组的区别
- 学习笔记——环境变量
- Android5.1.1源码
- 云计算基础(三):HDFS+MapReduce
- python中字符串连接的问题:
- My first technology blogs
- Android5.1.1源码