目录

Okio的诞生

OKio的简单介绍

缓存模块

超时机制

几个重要的类

简单的读写操作

一个简单的java+socket来实现请求服务器

在CacheInterceptor的运用

1)写请求的头部header

2)写请求体body的数据

3)向服务器发送数据

4)接收服务器的返回的头部header

5)读取服务器返回的response的body数据

总结


Okio的诞生

Okio是用来对数据进行存储和处理IO数据。

InputStream/

OutputStream

传统的IO,阻塞式IO操作,一直等到有数据才会返回。
NIO 非阻塞式IO。数据从通道(Channel)读取到缓冲区(Buffer),也可以从Buffer读取到Channel中。而Selector允许单线程处理多个通道,用来选出一个可用的通道。
Okio 增加了缓存机制、超时机制来实现快速访问、存储和处理IO数据

OKio的简单介绍

缓存模块

由Buffer、Segment、SegmentPool组成。Buffer采用的是有Segment组成的循环链表,来缓存数据;SegmentPool存放的是暂时不用的Segment的单链表,防止频繁进行删除数据操作

超时机制

1)Timeout

在处理InputStream和OutputStream时,传入的超时类,在使用Okio进行读写操作的时候,如果超时就通timeout.throwIfReached()抛出异常。

2)AsyncTimeout

异步超时类,通过一个线程在后台监听Socket是否有超时的操作。

几个重要的类

1)Source/Sink:

接口类。代表输入流和输出流,类似于InputStream/OutputStream,用来进行读写数据;

2)BufferedSource/BufferedSink:

分别继承Source/Sink,扩展了读写功能;

3)RealBufferedSource/RealBufferedSink:

BufferedSource/BufferedSink的实现类,用来完成数据的读写操作。查看里面的源码中可以发现,其实里面就是含有一个Source/Sink对象的代理和一个Buffer对象,真正的去完成读写操作的就是这个Buffer。

简单的读写操作

在使用Okio在进行读写文件的时候,首先要将文件转换成一个Source/Sink,然后在换成BufferedSource/BufferedSink,最后通过API直接读写数据

//获取文件
File file = new File(fileName);
//将file转换成Source
Source source = Okio.source(file);
//将source转换成BufferedSource
BufferedSource buff = Okio.buffer(source);
//读取BufferedSource里面的内容
String result = buff.readString(Charset.forName("utf-8"));

一个简单的java+socket来实现请求服务器

在用java的Socket来进行实现请求服务器的过程,向服务器发送数据就是从socket去取出OutputStream,然后将请求数据写入OutputStream;同样读取服务器返回的数据时,就是从socket中取出InputStream,然后从InputStream数据中读取即可。下面是简单的代码实例

1)向服务器发送数据

//向服务器发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("写数据".getBytes("UTF-8"));
outputStream.close();

2)接收服务器返回的数据

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//然后就等着服务器发送过数据之后,读取服务器发来的信息String line = null;StringBuffer buffer = new StringBuffer();
while ((line = bufferedReader.readLine()) != null) {buffer.append(line);
}

在CacheInterceptor的运用

1)写请求的头部header

  httpCodec.writeRequestHeaders(request);

这个httpCodec就是Http1Codec或者Http2Codec的实例。为了方便描述,我们拿Http1Codec举例说明。进入到Http1Codec源码中可以看到,最终调用的是下面的这个方法:

  public void writeRequest(Headers headers, String requestLine) throws IOException {if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);sink.writeUtf8(requestLine).writeUtf8("\r\n");for (int i = 0, size = headers.size(); i < size; i++) {sink.writeUtf8(headers.name(i)).writeUtf8(": ").writeUtf8(headers.value(i)).writeUtf8("\r\n");}sink.writeUtf8("\r\n");state = STATE_OPEN_REQUEST_BODY;}

其实就是往sink里面写入了请求头header的数据。 而这个sink是在RealConnection中创建链接通道的时,在实例化Http1Codec的时候,从RealConnection中传入的,而sink的实例化也在RealConnection中。

private void connectSocket(int connectTimeout, int readTimeout, Call call,EventListener eventListener) throws IOException {
//...代码省略source = Okio.buffer(Okio.source(rawSocket));sink = Okio.buffer(Okio.sink(rawSocket));
//...代码省略
}

进入到Okio中的sink()方法中,可以看到

  public static Sink sink(Socket socket) throws IOException {//.....代码省略Sink sink = sink(socket.getOutputStream(), timeout);return timeout.sink(sink);}

就是从socket中获取输出流进行转换成Sink,在经过buffer(),最终返回的是RealBufferedSink

  public static BufferedSink buffer(Sink sink) {return new RealBufferedSink(sink);}

所以我们在Http1Codec中的sink其实就是RealBufferedSink的对象实例。我们往sink中写入信息,其实就是写到了Buffer的缓存中。

2)写请求体body的数据

CountingSink requestBodyOut =new CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();

和写header的方式一样,先通过httpCodec.createRequestBody()来获取到请求body的数据,然后将数据转换成Sink,再将sink转换成BufferedSink,然后就是调用request().body().writeTo()方法进行将请求体body写入Buffer缓存中。看下request().body()返回的值body该对象就是在通过建造者模式创建Request的时候,在build()方法

  Request build() {
//.....代码省略RequestBody body = this.body;if (body == null) {// Try to pull from one of the builders.if (formBuilder != null) {body = formBuilder.build();} else if (multipartBuilder != null) {body = multipartBuilder.build();} else if (hasBody) {// Body is absent, make an empty body.body = RequestBody.create(null, new byte[0]);}}
//.....代码省略}

假设返回的是MultipartBody,那么最终调用的就是MultipartBody里面的writeTo()方法,进入到源码中可以看到也就是调用sink.write()来将body写入到Buffer的缓存中。

3)向服务器发送数据

 httpCodec.finishRequest();

真正的将数据发送给服务器。进入到Http1Codec看下finishRequest()源码:

  @Override public void finishRequest() throws IOException {sink.flush();}

调用的是RealBufferedSink的flush(),进入到RealBufferedSink中查看源码

  @Override public void flush() throws IOException {if (closed) throw new IllegalStateException("closed");if (buffer.size > 0) {sink.write(buffer, buffer.size);}sink.flush();}

最终调用的是的就是RealBufferedSink的write()

  @Override public void write(Buffer source, long byteCount)throws IOException {if (closed) throw new IllegalStateException("closed");buffer.write(source, byteCount);emitCompleteSegments();}

将请求信息写入到OutputStream中,完成将数据发送给服务器。

4)接收服务器的返回的头部header

    if (responseBuilder == null) {realChain.eventListener().responseHeadersStart(realChain.call());responseBuilder = httpCodec.readResponseHeaders(false);}

进入Http1Codec源码中查看

 @Override public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {//......省略代码try {StatusLine statusLine = StatusLine.parse(readHeaderLine());Response.Builder responseBuilder = new Response.Builder().protocol(statusLine.protocol).code(statusLine.code).message(statusLine.message).headers(readHeaders());//......省略代码}

通过readHeaderLine()将服务器返回的数据转换成StatusLine。其中通过source将返回的数据读出,而source的传入同1)中提到的sink的方式一样,都是在RealConnection中实例化时传入的。

  private String readHeaderLine() throws IOException {String line = source.readUtf8LineStrict(headerLimit);headerLimit -= line.length();return line;}

查看Okio中的Okio.source()的源码可以发现

  public static Source source(Socket socket) throws IOException {
//......省略代码AsyncTimeout timeout = timeout(socket);Source source = source(socket.getInputStream(), timeout);return timeout.source(source);}

该source()就是从socket的inputStream中读取数据。

5)读取服务器返回的response的body数据

response = response.newBuilder().body(httpCodec.openResponseBody(response)).build();

进入到源码中发现,在Http1Codec中的openResponseBody(),就是根据不同的条件返回RealResponseBody的对象。

  return new RealResponseBody(contentType, contentLength, Okio.buffer(source));

总结

Okio提供了阻塞IO和非阻塞IO的功能,同时增加了缓存和超时机制。在HttpCodec中通过Okio来实现读写服务器数据。

OkHttp的Okio在CacheInterceptor中的应用相关推荐

  1. android okhttp3 okio,OkHttp和Okio

    OkHttp和Okio 文本将介绍OkHttp和Okio基本使用 OkHttp HTTP 是现在APP访问网络最流行的方式.通过它我们可以交换数据和媒体信息.而高效的使用HTTP可以让你的加载数据更快 ...

  2. OkHttp –Android、Java应用中的 HTTP SPDY 客户端库

    原文链接: http://blog.chengyunfeng.com/?p=489 我们通过HTTP在设备和服务器之前交换数据.高效的使用HTTP可以让您的应用运行更快.更节省流量.而OkHttp库就 ...

  3. Okhttp 之 okio

    本文是的前一篇文章 Okhttp IO 之 Segment & SegmentPool 的基础上写的,如果你没看懂前面的文章,那么看本文会相当的吃力,因为很多关键的代码都是在前面这篇文章中剖析 ...

  4. android中okhttp原理详解,Android中okhttp原理详解-极度针对面试篇

    一.okhttp工做的大体流程 1.一.总体流程 (1).当咱们经过OkhttpClient创立一个Call,并发起同步或者异步请求时: (2).okhttp会经过Dispatcher对咱们全部的Re ...

  5. OKHttp之OkIO

    OKIO的核心:Sink和Souce okio的本质是对InputStream和OutputStream做了进一步封装 内部通过Segment组成的双向链表来持有数据

  6. Android/Java中okhttp用法介绍

    最近Android老项目改造, 之前老代码一直用AndroidHttpClient实现网络请求,存在以下问题 1. 版本太老旧, 最近无更新; 2.  网络请求模块代码太散乱,不好管理, 3. 不支持 ...

  7. java中的IO、NIO、Okio

    java IO 写 这种写方法只能一个字节一个字节的写: 注意把要关闭的流写在try括号中,省去了代码中finally关闭的过程,以下例子均是. private static void ioWrite ...

  8. Android中的OKHttp请求网络

    OKHttp 文章目录 OKHttp 一.简介 二.基本用法 1.依赖 2.使用OKHttp 2.1.get请求 2.2.post请求 3.案例操作演示(借助runOnUiThread()方法进行线程 ...

  9. Android—OkHttp同步异步请求过程源码分析与拦截器

    OkHttp同步请求步骤: 创建OkHttpClient,客户对象 创建Request,请求主体,在请求主体设置请求的url,超时时间等 用newCall(request)将Reuqest对象封装成C ...

最新文章

  1. String、StringBuffer与StringBuilder之间区别 (转载)
  2. 如何使用Spring优雅地处理REST异常?
  3. Drawable 详解
  4. LeetCode Algorithm 22. 括号生成
  5. 引发类型为“System.Windows.Forms.AxHost+InvalidActiveXStateException”的异常 解决
  6. MATLAB安装机器人学工具箱
  7. setnx是原子操作吗_Redis面试七连问,你能扛得住吗?
  8. react改变checkbox的文字类型_React Checkbox不发送onChange
  9. python输入路径读取文件-python获取程序执行文件路径的方法(推荐)
  10. 【图论】拓扑排序:一个名字高大上的实际很简单的算法(图文详解)
  11. PHP5.6中php-fpm的配置、启动、关闭和重启
  12. AI的委屈只有它知道……
  13. C++面向对象课程设计实例-图书馆借阅系统
  14. 做一个微信欢乐斗地主之残局解答器!
  15. Virtual-Taobao: Virtualizing Real-World Online Retail Environment for Reinforcement Learning
  16. 2020年鼠年正月二十一 雪中送炭难
  17. photoshop怎么设计淘宝天猫海报amp;nb…
  18. win10系统升级一段时间后,内存占用过高
  19. MiniFly微型四轴开发学习日志(一)——MiniFly 微型四轴软件原理
  20. python pandas 在现有excel中插入新数据

热门文章

  1. 5089. 安排会议日程
  2. React+echarts+antd实现折线图
  3. 使用webgl绘制一个点
  4. Linux系统中 chown和chmod 命令的区别:
  5. Barbalat引理与类李雅普诺夫引理,及它们在自适应控制系统设计的应用
  6. final、finalize 和 finally
  7. pycharm PEP8规范(python)
  8. Softing smartLink网关——推进过程工业数字化转型
  9. 在环仿真有两种,一种是软件在环仿真SITL,还有一种是硬件在环仿真HITL。
  10. 将GIF转成视频MP4、MOV