1. 程式人生 > >Android recyclerview原始碼分析(一)

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 itemmData[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 enlargeT[] 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方法都很簡單,就不分析了