前言
本篇是 IO系列 的第4篇,前三篇文章中,我们已经对JAVA经典IO设计、JAVA-NIO内容、操作系统IO架构基础概念、Zero-Copy做了较为系统的回顾。
而绝大部分Android应用中都会涉及到网络模块,Retrofit
、Okhttp
几乎是必用的框架, Okio
作为 Okhttp
中的重要模块,原先用于处理网络模块中的IO问题,随着其项目发展,Okio也开始面向其他问题。
这一篇,我们一同对OKIO做一次系统的梳理,搞明白OKIO为什么OK,做到在面试中自如的吹牛批、在日常工作中灵活使用。
编者按:面试吹牛批需要把握尺度,避免远超岗位预期,导致浪费时间
因文章篇幅较长,可结合内容导图阅读:
okio的主旨与架构
在OKIO项目的 wiki 中,对其主旨有如下介绍:
Okio is a library that complements java.io and java.nio to make it much easier to access, store, and process your data. It started as a component of OkHttp, the capable HTTP client included in Android. It’s well-exercised and ready to solve new problems.
简单直译为中文如下:
Okio是一个类库,对
java.io
和java.nio
进行了补充,使得访问、存储和处理数据变得更加容易。它最初是OkHttp的一个组件,OkHttp是安卓中的一个功能强大的HTTP客户端。它非常健壮,可以解决新问题。
简言之:为了更简单的访问、存储、处理数据,基于 java.io
和 java.nio
进行了功能补充
wiki中,简单介绍了设计中的几个重点角色:
- ByteStrings and Buffers
- Sources and Sinks
分层架构中相对扁平、简单:在应用和Java IO 之间增加了一层,即OKIO本身,包含 数据封装
、 输入输出
、 超时机制
体现在类图上还是比较复杂的:
在库内部,ByteStrings
的使用不多,对 Buffer
数据包装后为上层应用服务,单独拎出。
信息噪声比较多,去掉功能装饰的实现类后较为精简:
与Java的输入输出的对比
Java经典IO中的输入输出定义为Stream,在 系列文章 中进行了介绍。字符流类似,图略
在JDK的IO框架中,使用装饰模式建立了规模庞大、功能丰富的输入输出流。从OKIO的主旨出发,不难理解其设计者希望类库尽可能简单、易扩展、内建部分功能足够完善。因此,OKIO会适当的另起炉灶,不会全面的使用JDK中的Stream。
OKIO中使用了自定义的输入、输出,即 Source
和 Sink
,注意淡黄色、淡粉色部分:
Sink 在计算机领域有特定含义:指程序或者线程,可以接收数据,并且可以处理或者发送这些数据
差异点
在wiki中提到如下内容:
An elegant part of the java.io design is how streams can be layered for transformations like encryption and compression. Okio includes its own stream types called Source and Sink that work like InputStream and OutputStream, but with some key differences:
- Timeouts.
- Easy to implement.
- Easy to use.
- No artificial distinction between byte streams and char streams.
- Easy to test.
简单翻译下, Java IO的设计中有一处非常优雅:可以调整流的分层包装以实现加密、压缩等转换。OKIO包含自有的流类型 Source
、Sink
,与Java的 InputStream
、 OutputStream
功能类似,但是有几点关键的不同:
- 超时机制
- 更容易实现
- 更容易使用
- 字节流、字符流之间没有人为的差异
- 更容易测试
从输入方面看:
在JDK中,InputStream
使用多种层(以及复合层)处理种类繁多的各类数据
DataInputStream
用于处理基础数据类型BufferedInputStream
处理缓冲InputStreamReader
处理文本字符串
而OKIO在这些层之上建立了 BufferedSource
,Source避免了一些无法实现 available()
方法的困境, 转而由调用者指定它们需要的byte个数
在实现一个Source时,不必操心 read()
方法,它难以有效实现且需从257种值中返回一个 ,注:null & [0x00,0xFF]
从输出方面看:
类似的,在JDK中 OutputStream
使用多种层(以及复合层)处理种类繁多的各类数据,而Sink也非常容易采用分层设计
相同点
Source
、Sink
的功能与InputStream
、OutputStream
、Reader
、Writer
相同- 使用时可以通过装饰追加功能
对于功能相同,wiki中提到如下内容: