Android recyclerview源码分析(一)

源码分析基于22.2.1版本

先预览一下recyclerview 相关的类

 

今天先分析SortedList SortedListAdapterCallback

 

先看下这两个类的用法

 SortedList<Object> mDataList=new SortedList<>(Object.class, new ObjectListCallback(mAdapter));

 

 

 public class ObjectListCallback extends SortedListAdapterCallback<Object>{

 

        public ObjectListCallback(RecyclerView.Adapter adapter) {

            super(adapter);

        }

 

        @Override

        public int compare(Object o1, Object o2) {

            //TODO:

            return 0;

        }

 

        @Override

        public boolean areContentsTheSame(Object oldItem, Object newItem) {

            //TODO:

            return false;

        }

 

        @Override

        public boolean areItemsTheSame(Object item1, Object item2) {

            //TODO:

            return 0;

        }

}

 

再将mDataList传给RecyclerViewadapter就可以了,以后对mDataList的增删改查,都会通知adapter数据有变化,刷新界面。

 

其实重点是SortedList的分析,看看SortedList是如何实现列表的排序和操作的。

既然是List就一定有增删改查4个功能。

一、“增”:

1.1 add方法

private int add(T item, boolean notify) {
    int index = findIndexOf(item, mData, 0, mSize, INSERTION);//用二分法查找元素在列表中的位置
    if (index == INVALID_POSITION) {//如果没有,则将item放到第一个位置
        index = 0;
    } else if (index < mSize) {//如果item存在,则根据传入的SortedListAdapterCallback比较新item和旧item是否一样,比较规则用户决定
        T existing = mData[index];
        if (mCallback.areItemsTheSame(existing, item)) {
            if (mCallback.areContentsTheSame(existing, item)) {
                //no change but still replace the item
                mData[index] = item;
                return index;
            } else {
                mData[index] = item;
                mCallback.onChanged(index, 1);
                return index;
            }
        }
    }
    addToData(index, item);
    if (notify) {//通知adapter数据变化
        mCallback.onInserted(index, 1);
    }
    return index;
}

 

其中mCallback 

决定排序规则和通知adapter刷新界面

Add 涉及到findIndexOfaddToData方法

 

findIndexOf方法

private int findIndexOf(T item, T[] mData, int left, int right, int reason) {
    //因为linearEqualitySearch的存在,整个算法最坏的情形其实就是把列表每个元素都遍历一遍,需要N次,一般二分法最坏的情况应该是只要log[2]N次就能找到
    while (left < right) {//二分法查找
        final int middle = (left + right) / 2;
        T myItem = mData[middle];
        final int cmp = mCallback.compare(myItem, item);
        if (cmp < 0) {
            left = middle + 1;
        } else if (cmp == 0) {
            if (mCallback.areItemsTheSame(myItem, item)) {
                return middle;
            } else {
                int exact = linearEqualitySearch(item, middle, left, right);//线性查找,一个一个元素的比较
                if (reason == INSERTION) {
                    return exact == INVALID_POSITION ? middle : exact;
                } else {
                    return exact;
                }
            }
        } else {
            right = middle;
        }
    }
    return reason == INSERTION ? left : INVALID_POSITION;
}

 

原理是使用二分查找法,这个不多说。

 

addToData 主要做了两件事,扩展数组长度和空出index位置

private void addToData(int index, T item) {
    if (index > mSize) {
        throw new IndexOutOfBoundsException(
                "cannot add item to " + index + " because size is " + mSize);
    }
    if (mSize == mData.length) {//数组容量扩展,每次增加CAPACITY_GROWTH
        // we are at the limit enlarge
        T[] newData = (T[]) Array.newInstance(mTClass, mData.length + CAPACITY_GROWTH);
        //分两次复制,一次是index之前,一次是index之后
        System.arraycopy(mData, 0, newData, 0, index);
        newData[index] = item;
        System.arraycopy(mData, index, newData, index + 1, mSize - index);
        mData = newData;
    } else {
        // just shift, we fit
        //将index位置的item往后移一位
        System.arraycopy(mData, index, mData, index + 1, mSize - index);
        mData[index] = item;
    }
    mSize++;
}

 

 

1.2批量增加addAll

具体实现方法是addAllInternal

private void addAllInternal(T[] newItems) {
    final boolean forceBatchedUpdates = !(mCallback instanceof BatchedCallback);
    if (forceBatchedUpdates) {
        beginBatchedUpdates();
    }

    mOldData = mData;
    mOldDataStart = 0;
    mOldDataSize = mSize;

    Arrays.sort(newItems, mCallback);  // Arrays.sort is stable.

    final int newSize = deduplicate(newItems);
    if (mSize == 0) {//如果原来的列表数量为0,那么直接将新的列表赋值给mdata,省略合并的步骤
        mData = newItems;
        mSize = newSize;
        mMergedSize = newSize;
        mCallback.onInserted(0, newSize);
    } else {//合并
        merge(newItems, newSize);
    }

    mOldData = null;

    if (forceBatchedUpdates) {
        endBatchedUpdates();
    }
}

首先有个去重的方法deduplicate

这个方法的原理如下


 

 




addAllInternal中有个merge方法,里面有数组合并的算法,原理如下:

 

 



二、Removeupdataget方法都很简单,就不分析了

发布了14 篇原创文章 · 获赞 1 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览