写点什么

Android Glide 3,android 编程软件

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

// 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


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


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)

函数很长, 但是逻辑相对简单

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android Glide 3,android编程软件