Okio源码学习分析,成为一名合格Android架构师

本文详细分析了Okio库中Segment和Buffer的实现原理,探讨了Segment如何作为数据存储的基本单元,以及Segment的push、pop、split、compact等关键方法。同时介绍了Buffer的读写操作,特别是write方法如何处理数据写入和Segment的管理,以及read方法如何进行数据读取。文章还提到了SegmentPool的作用,用于缓存和回收Segment。最后,简述了ByteString类的功能,包括其与Buffer的交互以及各种编码转换方法。
摘要由CSDN通过智能技术生成

/**

  • Removes this segment of a circularly-linked list and returns its successor.

  • Returns null if the list is now empty.

*/

public @Nullable Segment pop() {

Segment result = next != this ? next : null;

prev.next = next;

next.prev = prev;

next = null;

prev = null;

return result;

}

/**

  • Appends {@code segment} after this segment in the circularly-linked list.

  • Returns the pushed segment.

*/

public Segment push(Segment segment) {

segment.prev = this;

segment.next = next;

next.prev = segment;

next = segment;

return segment;

}

/**

  • Splits this head of a circularly-linked list into two segments. The first

  • segment contains the data in {@code [pos…pos+byteCount)}. The second

  • segment contains the data in {@code [pos+byteCount…limit)}. This can be

  • useful when moving partial segments from one buffer to another.

  • Returns the new head of the circularly-linked list.

*/

public Segment split(int byteCount) {

if (byteCount <= 0 || byteCount > limit - pos) throw new IllegalArgumentException();

Segment prefix;

// We have two competing performance goals:

// - Avoid copying data. We accomplish this by sharing segments.

// - Avoid short shared segments. These are bad for performance because they are readonly and

// may lead to long chains of short segments.

// To balance these goals we only share segments when the copy will be large.

if (byteCount >= SHARE_MINIMUM) {

prefix = new Segment(this);

} else {

prefix = SegmentPool.take();

System.arraycopy(data, pos, prefix.data, 0, byteCount);

}

prefix.limit = prefix.pos + byteCount;

pos += byteCount;

prev.push(prefix);

return prefix;

}

/**

  • Call this when the tail and its predecessor may both be less than half

  • full. This will copy data so that segments can be recycled.

*/

public void compact() {

if (prev == this) throw new IllegalStateException();

if (!prev.owner) return; // Cannot compact: prev isn’t writable.

int byteCount = limit - pos;

int availableByteCount = SIZE - prev.limit + (prev.shared ? 0 : prev.pos);

if (byteCount > availableByteCount) return; // Cannot compact: not enough writable space.

writeTo(prev, byteCount);

pop();

SegmentPool.recycle(this);

}

/** Moves {@code byteCount} bytes from this segment to {@code sink}. */

public void writeTo(Segment sink, int byteCount) {

if (!sink.owner) throw new IllegalArgumentException();

if (sink.limit + byteCount > SIZE) {

// We can’t fit byteCount bytes at the sink’s current position. Shift sink first.

if (sink.shared) throw new IllegalArgumentException();

if (sink.limit + byteCount - sink.pos > SIZE) throw new IllegalArgumentException();

System.arraycopy(sink.data, sink.pos, sink.data, 0, sink.limit - sink.pos);

sink.limit -= sink.pos;

sink.pos = 0;

}

System.arraycopy(data, pos, sink.data, sink.limit, byteCount);

sink.limit += byteCount;

pos += byteCount;

}

}

首先,Segment中有几个成员变量:Segment.SIZE这个值是8192,也就是8kb, 是一个Segment对象能处理的数据的大小,byte[] data这个就是真正的存储数据的字节数组,pos这个是读取数据的起始位置,limit是写数据的起始位置,shared表示当前Segment的字节数组data是否可以共享的,owner表示当前Segment是否是data对象的持有者(只有data对象的持有者才能对data进行修改), 只有share为false即表示owner为true是当前的持有者。这里有个概念就是share “共享”,Segment中的data数组是可以在Buffer和ByteString对象之间共享的,怎么来确认这个共享呢,我们看到Segment对象有三个构造函数,其中有参的构造函数:

Segment(Segment shareFrom) {

this(shareFrom.data, shareFrom.pos, shareFrom.limit);

shareFrom.shared = true;

}

Segment(byte[] data, int pos, int limit) {

this.data = data;

this.pos = pos;

this.limit = limit;

this.owner = false;

this.shared = true;

}

也就是通过外部传递Segment对象和data数组的方式构造出来的Segment就是共享的,而默认的构造函数:

Segment() {

this.data = new byte[SIZE];

this.owner = true;

this.shared = false;

}

这样出来的就是不共享的Segment对象。

继续,nextprev就是分别代表后继节点和前驱节点的对象,并以此来形成双向链表,那么怎么形成的双向链表呢?就是通过调用push方法,具体先放着,后面看Buffer的时候再细看。Segment中的主要方法为pop()push()split()compact(),其中pop()方法的作用是将当前的Segment对象从双向链表中移除,并返回链表中的下一个结点作为头结点,而push()方法的作用则是在双向链表中当前结点的后面插入一个新的Segment结点对象,并移动next指向新插入的结点。后面两个方法主要是对Segment进行分割和合并,

提到Segment,还有一个与之相关的类SegmentPool类:

/**

  • A collection of unused segments, necessary to avo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值