Android Glide 3,android 编程软件
// buf 缓存从流中读取出来的数据 private volatile byte[] buf;// buf 有效数据的长度 private int count;// mark 标记数据的长度 private int marklimit;// mark 标记的位置, 默认 -1 表示没有标记 private int markpos = -1;// 当前读取 buf 的位置 private int pos;
}
mark() 和 reset()
再来看看 mark 和 reset 方法
public synchronized void mark(int readlimit) {marklimit = Math.max(marklimit, readlimit);markpos = pos;}
public synchronized void reset() throws IOException {if (buf == null) {throw new IOException("Stream is closed");}if (-1 == markpos) {throw new InvalidMarkException("Mark has been invalidated");}pos = markpos;}
mark 就做了两件事 赋值 + 赋值
marklimit 和旧的作比较取一个最大值
markpos 设置为当前读取位置
reset 就做了一件事
当前位置 pos 被重置成 markpos
read()
来看看 read 方法干了啥
public synchronized int read() throws IOException {// Use local refs since buf and in may be invalidated by an// unsynchronized close()byte[] localBuf = buf;InputStream localIn = in;if (localBuf == null || localIn == null) {throw streamClosed();}
// Are there buffered bytes available?if (pos >= count && fillbuf(localIn, localBuf) == -1) {// no, fill bufferreturn -1;}// localBuf may have been invalidated by fillbufif (localBuf != buf) {localBuf = buf;if (localBuf == null) {throw streamClosed();}}
// Did filling the buffer fail with -1 (EOF)?if (count - pos > 0) {return localBuf[pos++] & 0xFF;}return -1;}
这个 read() 方法是读取单个字符用的, 每次只读去 1 个 byte 返回
pos >= count 代表
buf
被读完了, 调用 fillbuf(localIn, localBuf) 去重新向buf
填充数据count - pos > 0 代表
buf
数据还够, 直接读取返回 localBuf[pos++] & 0xFF
这里 return 为毛是个 int ??? 说好的 byte 呢 因为返回的流数据里面是无符号的 byte 0~255 范围 , 而 java 里面的 byte 默认带符号, - 128 ~ 127, 数据范围不够, 只能用 int 来凑了, 注意这行代码:
localBuf[pos++] & 0xFF
, 把高 24 位全部清零了, 达到返回 0~255 效果
这中间好像没有提到 mark 的部分, 猜测只能是在 fillbuf
函数中实现了, 跟进去看看
fillbuf()
代码较长, 耐心看看
private int fillbuf(InputStream localIn, byte[] localBuf)throws IOException {// 没有标记, 或者读取区域超过了标记的范围, 直接从流中读取数据到 bufif (markpos == -1 || pos - markpos >= marklimit) {// Mark position not set or exceeded readlimitint result = localIn.read(localBuf);if (result > 0) {markpos = -1;pos = 0;count = result;}return result;}
// [标记有效] 这里 buf.length 不够了, 扩容 2 倍 if (markpos == 0 && marklimit > localBuf.length && count == localBuf.length) {// Increase buffer size to accommodate the readlimitint newLength = localBuf.length * 2;if (newLength > marklimit) {newLength = marklimit;}if (Log.isLoggable(TAG, Log.DEBUG)) {Log.d(TAG, "allocate buffer of length: " + newLength);}byte[] newbuf = new byte[newLength];System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length);localBuf = buf = newbuf;}
// [标记有效] 标记位置 >0 buf 中 标记位置之前还有一批数据可以被舍弃 else if (markpos > 0) {System.arraycopy(localBuf, markpos, localBuf, 0, localBuf.length
markpos);}// 重置读取位置和 buf 中有效数据的长度 pos -= markpos;count = markpos = 0;// 如果 buf 不满(还有脏数据) 就开始从流中读取填充 int bytesread = localIn.read(l
ocalBuf, pos, localBuf.length - pos);count = bytesread <= 0 ? pos : pos + bytesread;return bytesread;}
以上一共有三种情况
第一种: 没有 mark 参与或者 mark 已失效 (
markpos == -1 || pos - markpos >= marklimit
), 就是普通的从流中读取数据, 填满 buf , 然后把 pos 当前读取位置重置一下 ( 下图绿色表示扩容部分 )
第二种, (
markpos == 0 && marklimit > localBuf.length && count == localBuf.length
) mark 有效, 且 markpos 左侧已经退不可退, 抵到 buf 的最左侧了; 并且 marklimit 超过了 buf 的长度;且
count == localBuf.length
才进行 2 倍扩容
看
count == localBuf.length
这个条件, 他表示 buf 里面的有效数据必须是满的才进行扩容, buf 只有在读到文件末尾时才可能不满, 当流都读完了, 没数据了, 即使 marklimit 超过 buf 的长度也没必要扩容了, 根本读不到那么多了;看这几行代码
int newLength = localBuf.length * 2;if (newLength > marklimit) {newLength = marklimit;}
如果扩充 2 倍后大于 marklimit 则以 marklimit 为准, 否则, 就只扩充 2 倍, 不会一下子扩充到 marklimit 的大小, 对内存的使用可谓是抠搜到极致 ( 可以理解为懒申请, 用到了才去申请更大的 buf )
第二种情况 扩容一: marklimit < buf.length * 2 的情况
2 倍超出 marklimit 的长度, 直接以 marklimit 的长度为准, 上图绿色为扩容部分
第二种情况 扩容二: marklimit >= buf.length * 2 的情况
第三种情况 markpos != 0 并且不满足扩容条件
这种情况下, 只需要把 markpos 左边的数据清除, 然后再往 buf 右边空出的位置写入数据
至此, fillbuf()
分析完毕, 一种分三种情况来填充 buf
上面都已做出图示说明
read(byte[] buffer, int offset, int byteCount)
函数很长, 但是逻辑相对简单
评论