RecyclerView ChildHelper源码

2020/05/11 Android

RecyclerView childHelper 源码分析

大纲: 
1. ChildHelper的职责
2. hidden的处理方式
2. 关于Bucket的位计算

概述

ChildHelper帮助处理RecyclerView中的View的辅助类。 RecyclerView中的childern被分成了2类一类是当前正在使用可见的,一类是hidden的。ChildHelper提供了2类方法,一类获取getChildCount等,一类是Unfilter的方法 例如getUnfilterChildCount , 区别是getChildCount返回当前可见的View的个数,getUnfilterChildCount返回未过滤的View在ViewGroup中的实际个数。

Unfilter

关注过滤掉的是什么,过滤掉的是不可见的View, 即被缓存起来留着复用的View

    // index为可见View中的下标,计算出真正的位置并返回
    View getChildAt(int index) {
        final int offset = getOffset(index);
        return mCallback.getChildAt(offset);
    }

    // index为view的实际位置
    View getUnfilteredChildAt(int index) {
        return mCallback.getChildAt(index);
    }

    // 获取可见View中位置index 对应的ViewGroup中的实际位置
    private int getOffset(int index) {
        if (index < 0) {
            return -1; //anything below 0 won't work as diff will be undefined.
        }
        final int limit = mCallback.getChildCount();
        int offset = index;
        while (offset < limit) {
            final int removedBefore = mBucket.countOnesBefore(offset);
            // 改成(index+removedBefore) - offset更好理解 可见的View的个数加上现在计算出的不可见的View的个数最终应该和实际的个数offset相同
            final int diff = index - (offset - removedBefore);
            if (diff == 0) {
                while (mBucket.get(offset)) { // ensure this offset is not hidden
                    offset++;
                }
                return offset;
            } else {
                offset += diff;
            }
        }
        return -1;
    }

Bucket

用来帮助管理哪些View可见 哪些是hidden的,使用位计算来标记View的当前状态。

    static class Bucket {

        static final int BITS_PER_WORD = Long.SIZE;

        static final long LAST_BIT = 1L << (Long.SIZE - 1);

        long mData = 0;

        Bucket mNext;

        ......
    }

用一个64位的二进制表示,哪一位为1表示这个位置的View是隐藏状态的 比如 00001010 表示下标为 1 和 3位置的View是隐藏的。当超过64的存储在mNext中

set

      // 标记某个位置的View 为hidden
      void set(int index) {
            // mData中只能记录64个信息,超过的部分记录到mNext中(方法很巧妙值得借鉴)
            if (index >= BITS_PER_WORD) {
                ensureNext();
                mNext.set(index - BITS_PER_WORD);
            } else {
                // 将对应位置标记为1
                mData |= 1L << index;
            }
        }

insert

      // 修改某一位的值, value 为true 修改为1 为false 修改为0
      void insert(int index, boolean value) {
            // 超过64的交给mNext处理
            if (index >= BITS_PER_WORD) {
                ensureNext();
                mNext.insert(index - BITS_PER_WORD, value);
            } else {
                // 暂时记录最后一位的值,最终会移动到mNext中
                final boolean lastBit = (mData & LAST_BIT) != 0;
                // 帮助记录插入位置右边的记录,可以得到 00001111111 的标记
                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 || mNext != null) {
                    ensureNext();
                    mNext.insert(0, lastBit);
                }
            }
        }

remove

 // 移除某一位的数据
  boolean remove(int index) {
            // 超过64的交给mNext处理
            if (index >= BITS_PER_WORD) {
                ensureNext();
                return mNext.remove(index - BITS_PER_WORD);
            } else {
                // 获取到 100000000的mask
                long mask = (1L << index);
                // 获取要移除位置的值是否为1
                final boolean value = (mData & mask) != 0;
                // ~mask 的值大概为 1111111011111111 即清空要移除位置的值 将其记录为0用于之后循环右移
                mData &= ~mask;
                // mask 修改为 00000001111111111
                mask = mask - 1;
                // 获取到右侧(要删除区域前面的值)
                final long before = mData & mask;
                // 循环右移一位 高位补0 即移除既定位置后的上半区域的值
                // cannot use >> because it adds one.
                final long after = Long.rotateRight(mData & ~mask, 1);
                // 合并成最终的值
                mData = before | after;
                // 处理mNext
                if (mNext != null) {
                    if (mNext.get(0)) {
                        set(BITS_PER_WORD - 1);
                    }
                    mNext.remove(0);
                }
                return value;
            }
        }

countOnesBefore

        // 记录对应位置前有多少hidden状态的View
        int countOnesBefore(int index) {
            if (mNext == 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 mNext.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData);
            }
        }

欢迎关注我的微信公众号

璐豪笔记

CoderHouse

Search

    Post Directory