RecyclerView学习笔记(1) ChildHelper.Bucket

来源:互联网 发布:csol刀战优化 编辑:程序博客网 时间:2024/06/01 09:44

    • 简介
      • toString方法
      • set方法
      • get方法
      • clear方法
      • countOnesBefore方法
      • reset方法
      • insert方法
      • remove方法
      • 总结

简介

RecyclerView中的ChildHelper.Bucket是一个工具类,实现了类似List<Boolean>的数据结构,从而达到减少内存占用的目的。
Bucket是一个链表结构,有两个字段:mData用于存储当前信息,next指向下一个数据

public 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;//指向下一个数据}

mData是long类型,存在64个bit位,每一个bit位可以是0或者1,代表true或false。这样一个mData可以存储64个(long类型的位数)true或false信息。相对于List<Boolean>,而且是最多64位。当然,如果需要集合的大小超过了64,则相关的信息存储到了next中,这就是使用链表的作用了吧。

toString方法

链式调用next,打印mData的二进制字符串,不同的buckt用xx分隔(后面有使用示例)

@Override        public String toString() {            return next == null ? Long.toBinaryString(mData)                    : next.toString() + "xx" + Long.toBinaryString(mData);        }

调用端代码:

Log.i(TAG,bucket.toString());//0        bucket.set(65);        Log.i(TAG,bucket.toString());//10xx0

set方法

设置对应index位的bit为1(index从0开始)

public void set(int index) {            if (index >= BITS_PER_WORD) {//如果index大于等于64,则相关信息设置到next中                ensureNext();                next.set(index - BITS_PER_WORD);            } else {                mData |= 1L << index;            }        }

调用端代码:

ChildHelper.Bucket bucket = new ChildHelper.Bucket();bucket.set(3);Log.i(TAG,bucket.toString());//1000

从结果可以看到:idex为3的位置的bit已经被设置成1了

get方法

判断index对应的bit是否为1,如果为1,返回true,否则返回false。

public boolean get(int index) {            if (index >= BITS_PER_WORD) {//如果index大于等于64,则从next中获取                ensureNext();                return next.get(index - BITS_PER_WORD);            } else {                return (mData & (1L << index)) != 0;            }        }

调用端代码:

bucket.set(4);Log.i(TAG,bucket.toString());//10000boolean has4 = bucket.get(4);Log.i(TAG,"has4=" + has4);//has4=true

可以看到index为4的bit为1,就返回了true

clear方法

设置index对应的bit为0

public void clear(int index) {            if (index >= BITS_PER_WORD) {//如果index大于等于64,则设置next中相应数据                if (next != null) {                    next.clear(index - BITS_PER_WORD);                }            } else {                mData &= ~(1L << index);            }        }

调用端代码:

bucket.set(3);        Log.i(TAG,bucket.toString());//1000        bucket.clear(3);        Log.i(TAG,bucket.toString());//0

可以看到index为3对应的bit已经被设置成0

countOnesBefore方法

计算比index小的所有位数上bit为1的总个数。
例如 0001 1010,如果index为5,则结果为3;如果index为4,则结果是2

public 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);            }        }

调用端代码:

bucket.set(4);        Log.i(TAG,bucket.toString());//10000        boolean has4 = bucket.get(4);        Log.i(TAG,"has4=" + has4);//has4=true        bucket.set(3);        bucket.set(2);        Log.i(TAG,bucket.toString());//11100        int i = bucket.countOnesBefore(5);        Log.i(TAG,"i=" + i);//i=3(前5位中bit为1的总数)        int j = bucket.countOnesBefore(4);        Log.i(TAG,"j=" + j);//j=2(前4位中bit为1的总数)

可以看到,如果当前bucket为11100,则countOnesBefore(5)为3,countOnesBefore(4)为2。

reset方法

重置,所有数据置为0

public void reset() {            mData = 0;            if (next != null) {                next.reset();            }        }

调用端代码:

bucket.set(65);        Log.i(TAG,bucket.toString());//10xx0        bucket.reset();        Log.i(TAG,bucket.toString());//0xx0

insert方法

在index位置插入指定bit:value为true插入1,value为false插入0

public void insert(int index, boolean value) {            if (index >= BITS_PER_WORD) {//如果index大于等于64,则在next中插入                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;//小于index的数据                final long after = ((mData & ~mask)) << 1;//大于index的数据,已经左移一位,腾出当前位置                mData = before | after;                if (value) {                    set(index);//value为ture插入1                } else {                    clear(index);//value为false插入0                }                if (lastBit || next != null) {                    ensureNext();                    next.insert(0, lastBit);//将当前bucket最高位的bit插入到next的index为0的位置上(实现左移操作)                }            }        }

调用端代码:

bucket.reset();        Log.i(TAG,bucket.toString());//0xx0        bucket.set(6);        bucket.set(5);        Log.i(TAG,bucket.toString());//0xx1100000        bucket.insert(6,false);        Log.i(TAG,bucket.toString());//0xx10100000(6和5之间插入一位,插入的值为0)        bucket.insert(6,true);        Log.i(TAG,bucket.toString());//0xx101100000(6和5之间插入一位,插入的值为0)

可以看到在index为6的位置上插入了指定bit,低于6的数据保持不变,大于等于6的数据左移了一位

remove方法

移除index对应位置的bit。低于index的所有数据保持不变,高于index的数据右移一位。

public boolean remove(int index) {            if (index >= BITS_PER_WORD) {//如果index大于等于64,则在next中移除                ensureNext();                return next.remove(index - BITS_PER_WORD);            } else {                long mask = (1L << index);                final boolean value = (mData & mask) != 0;                mData &= ~mask;//index未bit置为0                mask = mask - 1;                final long before = mData & mask;//小于index的数据                // cannot use >> because it adds one.                final long after = Long.rotateRight(mData & ~mask, 1);//大于index的数据(已右移一位)                mData = before | after;                if (next != null) {//如果next存在                    if (next.get(0)) {//如果next的index为0的bit为1                        set(BITS_PER_WORD - 1);//设置当前最高位的bit为1(相当于右移一位)                    }                    next.remove(0);//next需要进行:删除index为0的操作                }                return value;            }        }

调用端代码:

Log.i(TAG,bucket.toString());//0xx101100000(6和5之间插入一位,插入的值为0)bucket.remove(6);Log.i(TAG,bucket.toString());//0xx10100000(移除位置6的bit)

可以看到index为6的bit删除了,低于6的数据保持不变,高于6的数据全部右移了一位

总结

Bucket通过链表的数据结构和long类型可以存储64位bit为1或0的特性,实现了类似List<Boolean>的数据结构,从而达到减少内存占用的目的。

原创粉丝点击