是在阅读RecyclerView的源码时, 在里面发现了该部分代码, 觉得很有趣, 故记录一下.
该部分代码用于实现了bitmap, 在RecyclerView的包中用于管理子view.
代码位于RecyclerView包的 ChildHelper.java 文件, 是一个子类, 类名为 Bucket.
介绍
该类使用一个 LONG链表 作为bitmap的存储器, 该结构的主要特点包括:
理论上可以存放无限多个bit.
支持动态扩展.
支持添加/删除/插入/统计等操作.
代码实现
成员变量
该类只有四个变量, BITS_PER_WORD代笔每个Bucket对象可以存放的bit数量, 这里使用了Long类型, 故可以存放64位. mData是具体存放bit的数据, next指向下一个Bucket对象.
static class Bucket { final static int BITS_PER_WORD = Long.SIZE; final static long LAST_BIT = 1L << (Long.SIZE - 1); long mData = 0; Bucket next;
设置bit: set(index)
set(int index)
函数用于将index位置的bit设置为1.
该函数首先检查要插入的位置, 是不是大于当前的Bucket的范围,
如果不大于, 那么通过 "或" 来设置该bit位.
如果大于, 先调用ensureNext()函数确定是否需要生成一个新 的Bucket放到链表尾部, 然后调用下个Bucket的set()函数, 但是传入的参数 为 index 减去当前Bucket的长度(64). 如果下个bucket还是不满足, 会一直 顺着链表调用下去, 直到找到一个合适的位置.
void set(int index) { if (index >= BITS_PER_WORD) { ensureNext(); next.set(index - BITS_PER_WORD); } else { mData |= 1L << index; }}
ensureNext()的代码如下:
private void ensureNext() { if (next == null) { next = new Bucket(); }}
清除操作: clear(index)
其原理跟设置一样, 通过 "与" 操作将bit位清除.
void clear(int index) { if (index >= BITS_PER_WORD) { if (next != null) { next.clear(index - BITS_PER_WORD); } } else { mData &= ~(1L << index); }}
判断: get(index)
递归查找链表, 判断指定位置是否设置了bit位.
boolean get(int index) { if (index >= BITS_PER_WORD) { ensureNext(); return next.get(index - BITS_PER_WORD); } else { return (mData & (1L << index)) != 0; }}
插入: insert(index, b)
在指定的位置插入一个bit的设置, 该位置后面的内容后移. 这个操作是通过下述步骤实现:
先获取该位置之前位置的mask:
long mask = (1L << index) - 1;
通过"与"操作获取该位置之前的内容.
通过"与"操作与"移位"操作将该位置之后的内容后移一位.
使用第二个参数设置该位置的bit值.
注: 如果插入之前, Bucket对象的最高位的bit被设置(为1), 那么在后移过程中, 该位置会被移除该Bucket, 所以需要记录下来, 将其重新插入到下一个Bucket中. 这个过程会一直持续下去, 直到碰到一个最高位没被设置的Bucket.
void insert(int index, boolean value) { if (index >= BITS_PER_WORD) { ensureNext(); next.insert(index - BITS_PER_WORD, value); } else { final boolean lastBit = (mData & LAST_BIT) != 0; long mask = (1L << index) - 1; final long before = mData & mask; final long after = ((mData & ~mask)) << 1; mData = before | after; if (value) { set(index); } else { clear(index); } if (lastBit || next != null) { ensureNext(); next.insert(0, lastBit); } }}
移除: remove(index)
该函数用于将该位置的bit位移除, 并将其后面的bit前移一位. 该函数的步骤:
通过"与"操作将index位置的bit设为0.
缓存index之前的数据.
调用Long.rotateRight(), 将index之后的数据前移一位. 因为rotate之前已经将前面(低位)的数据置位0, 所以rotate之后 最高位一直是0.
将第2步和第3步的数据合并成新数据.
判断下一个Bucket的第一位是否为1. 如果是则将该bucket的最高位置1.
调用下一个bucket的remove(0). 遍历链表, 重复这个操作.
boolean remove(int index) { if (index >= BITS_PER_WORD) { ensureNext(); return next.remove(index - BITS_PER_WORD); } else { long mask = (1L << index); final boolean value = (mData & mask) != 0; mData &= ~mask; mask = mask - 1; final long before = mData & mask; // cannot use >> because it adds one. final long after = Long.rotateRight(mData & ~mask, 1); mData = before | after; if (next != null) { if (next.get(0)) { set(BITS_PER_WORD - 1); } next.remove(0); } return value; }}
统计: countOnesBefore(index)
统计index之前的bit数量. 基于 Long 的 bitCount() 函数实现.
int countOnesBefore(int index) { if (next == null) { if (index >= BITS_PER_WORD) { return Long.bitCount(mData); } return Long.bitCount(mData & ((1L << index) - 1)); } if (index < BITS_PER_WORD) { return Long.bitCount(mData & ((1L << index) - 1)); } else { return next.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData); }}
共同学习,写下你的评论
评论加载中...
作者其他优质文章