OkHttp 是一套处理 HTTP 网络请求的依赖库,由 Square 公司设计研发并开源,目前可以在 Java 和 Kotlin 中使用。底层的IO读取是Okio库。它补充了Java.io和java.nio的不足,以便能够更加方便,快速的访问、存储和处理数据。
1 2 3 4 5 6 OkHttpClient client = new OkHttpClient ();Request request = new Request .Builder().url(url).build();client.newCall(request).enqueue(new Callback (){ onResponse(); onFailure(); })
还可以使用Builder来创建OkHttpClient
1 2 3 4 5 6 OkHttpClient.Builder builder = new OkHttpClient .Builder(); builder.connectTimeout() .addInterceptor() .proxy() .cache(); OkHttpClient client = builder.build();
newCall方法 这个方法会返回一个 RealCall 类型的对象,通过RealCall可以将网络请求操作添加到请求队列中(即下方的Dispatcher方法)。return RealCall.newRealCall(request);
enqueue方法 调用 Dispatcher 的入队方法,执行一个异步网络请求的操作。client.dispatcher().enqueue(new AsyncCall(responseCallback));
enqueue(call)
executorService().execute(call)
可以看出,实际上就是使用线程池执行了一个 AsyncCall,而 AsyncCall 实现了 Runnable 接口,因此整个操作会在一个子线程(非 UI 线程)中执行。
继续查看 AsyncCall 中的 run 方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public abstract class NamedRunnable implements Runnable { @Override public final void run () { execute(); } protected abstract void execute () ; } final class AsyncCall extends NamedRunnable { @Override protected void execute () { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { responseCallback.onFailure(RealCall.this , new IOException ("Canceled" )); } else { responseCallback.onResponse(RealCall.this , response); } }
责任链 真正获取请求结果的方法是在 getResponseWithInterceptorChain 方法中,从名字也能看出其内部是一个拦截器的调用链,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Response getResponseWithInterceptorChain () throws IOException { 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, this , eventListener, client.connectTimeoutMillis(), client.readTimeoutMillis(), client.writeTimeoutMillis()); return chain.proceed(originalRequest); }
client.interceptors :自定义拦截器
BridgeInterceptor:主要对 Request 中的 Head 设置默认值,比如 Content-Type、Keep-Alive、Cookie 等。
CacheInterceptor:负责 HTTP 请求的缓存处理。
ConnectInterceptor:负责建立与服务器地址之间的连接,也就是 TCP 链接。
CallServerInterceptor:负责向服务器发送请求,并从服务器拿到远端数据结果。
1 2 3 4 5 6 RealInterceptorChain next = new RealInterceptorChain (interceptors, streamAllocation, httpCodec, connection, index + 1 , request, call, eventListener, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index);Response response = interceptor.intercept(next);
这里首先去获取传入的interceptors(拦截器列表)取出下一个拦截器,并调用拦截器的intercept方法,并传入下一个RealInterceptorChain对象供当前拦截器调用。 然后每个拦截器根据会根据情况,拿到传入的RealInterceptorChain调用chain.proceed,调用下一个拦截器。
CacheInterceptor 缓存拦截器 CacheInterceptor 主要做以下几件事情:
根据 Request 获取当前已有缓存的 Response(有可能为 null),并根据获取到的缓存 Response,创建 CacheStrategy 对象。
通过 CacheStrategy 判断当前缓存中的 Response 是否有效(比如是否过期),如果缓存 Response 可用则直接返回,否则调用 chain.proceed() 继续执行下一个拦截器,也就是发送网络请求从服务器获取远端 Response。
如果从服务器端成功获取 Response,再判断是否将此 Response 进行缓存操作。
OkHttp 提供了一个默认的缓存类 Cache.java,我们可以在构建 OkHttpClient 时,直接使用 Cache 来实现缓存功能。只需要指定缓存的路径,以及最大可用空间即可,如下所示:
builder.cache(new Cache(getCacheDir(),1024*1024*10))
Cache 内部使用了 DiskLruCach 来实现具体的缓存功能,DiskLruCache 最终会以 journal 类型文件将需要缓存的数据保存在本地。
CallServerInterceptor CallServerInterceptor 是 OkHttp 中最后一个拦截器,也是 OkHttp 中最核心的网路请求部分,其 intercept 方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public Response intercept (Chain chain) throws IOException {realChain.eventListener().requestHeadersStart(realChain.call()); httpCodec.writeRequestHeaders(request); realChain.eventListener().requestHeadersEnd(realChain.call(), request); httpCodec.finishRequest(); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - …… response = response.newBuilder() .body(httpCodec.openResponseBody(response)) .build(); }
OkHttp 监听下载进度 retrofit : 在onNext中 直接监听文件的写入
okhttp: 自定义responseBody继承ResponseBody,初始化okhttp时添加自定义拦截器