RecyclerView学习笔记(1) ChildHelper.Bucket

简介

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());//10000
boolean 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>的数据结构,从而达到减少内存占用的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值