两个重要的域
private View[] mActiveViews = new View[0]; //屏幕上显示的Item
private ArrayList<View>[] mScrapViews;//移除屏幕的Item
重要的方法
public void markChildrenDirty() // 该方法标记出移除屏幕的item 用forcelayout函数。(该函数没找到)
void fillActiveViews(int childCount, int firstActivePosition)//通过传入的firstActiovePosition来初始化mActiveViews数组
发现一个问题
int[] test1 = { 1, 1, 1, 1 };
int[] test2 = test1;
test2[0] = 0;
会发现test1 test2都变了,因为=赋值是把地址指针赋值了,所以两个数组指向的其实是一个东西。
而在recycleBin中经常这样用:
final View[] activeViews = mActiveViews;
在对activeViews进行操作;不知道是不是会有性能上的优势。而且final的值是不能变得啊,为什么会写activeViews[index] = null;(实际上值是可变的)
重要函数:将移出屏幕的view加入scrapyview。参数scrap是被移出的view,position是其在父类中的位置。
void addScrapView(View scrap, int position) {
final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
if (lp == null) {
// Can't recycle, but we don't know anything about the view.
// Ignore it completely.
//啥也不知道,直接就没法加
return;
}
lp.scrappedFromPosition = position;
// Remove but don't scrap header or footer views, or views that
// should otherwise not be recycled.
final int viewType = lp.viewType;
if (!shouldRecycleViewType(viewType)) {
// Can't recycle. If it's not a header or footer, which have
// special handling and should be ignored, then skip the scrap
// heap and we'll fully detach the view later.
//如果不为header或者footer,就skip the scrapy,先跳过,将其储存在一个list中,等一会再detach(此处意思应该为拆分?)
if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
getSkippedScrap().add(scrap);
}
return;
}
scrap.dispatchStartTemporaryDetach();
// The the accessibility state of the view may change while temporary
// detached and we do not allow detached views to fire accessibility
// events. So we are announcing that the subtree changed giving a chance
// to clients holding on to a view in this subtree to refresh it.
//不懂,无视
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
// Don't scrap views that have transient state.
//什么事transient state? transient意为短暂的,暂时的。
final boolean scrapHasTransientState = scrap.hasTransientState();
if (scrapHasTransientState) {
if (mAdapter != null && mAdapterHasStableIds) {
// If the adapter has stable IDs, we can reuse the view for
// the same data.
//此处有意思,如果每个view的lp都有单独的id,那么就把这些个view和其id存在一个表里,下次再读到这个id时就取用 // mTransientStateViewsById中的数据就好
if (mTransientStateViewsById == null) {
mTransientStateViewsById = new LongSparseArray<>();
}
mTransientStateViewsById.put(lp.itemId, scrap);
} else if (!mDataChanged) {
// If the data hasn't changed, we can reuse the views at
// their old positions.
//在没有stableid的情况下,如果数据不变(这是怎么判断的呢?)着直接可以用原位置上的view
if (mTransientStateViews == null) {
mTransientStateViews = new SparseArray<>();
}
mTransientStateViews.put(position, scrap);
} else {
// Otherwise, we'll have to remove the view and start over.
//其他情况下就只能把这个transientview加入到skippedscrapy中去了。
getSkippedScrap().add(scrap);
}
} else {
//如果不在transient状态下
if (mViewTypeCount == 1) {
mCurrentScrap.add(scrap);
} else {
mScrapViews[viewType].add(scrap);
}
if (mRecyclerListener != null) {
mRecyclerListener.onMovedToScrapHeap(scrap);
}
}
}
//重要函数,参数scrapViews是分两种情况,如果是一个布局就是mCurrentScrap,如果是多个布局就是mScrapyViews[]
private View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
final int size = scrapViews.size();
if (size > 0) {
// See if we still have a view for this position or ID.
for (int i = 0; i < size; i++) {
final View view = scrapViews.get(i);
final AbsListView.LayoutParams params =
(AbsListView.LayoutParams) view.getLayoutParams();
if (mAdapterHasStableIds) {
//遍历数组,如果是view有stableId 的情况下,则将同id 的view移除scrapviews。
final long id = mAdapter.getItemId(position);
if (id == params.itemId) {
return scrapViews.remove(i);
}
} else if (params.scrappedFromPosition == position) {
//如果是从同一个位置scrap掉的,则返回这个位置的scrapview
final View scrap = scrapViews.remove(i);
clearAccessibilityFromScrap(scrap);
return scrap;
}
}
//如果都不是,则返回最后的一个scrap
final View scrap = scrapViews.remove(size - 1);
clearAccessibilityFromScrap(scrap);
return scrap;
} else {
return null;
}
}
//此处是转载http://blog.csdn.net/linghu_java/article/details/39496921的一段分析
1. 如果有view.scrappedFromPosition = position的,直接返回该view;
2. 否则返回mScrapView中最后一个;
3. 如果缓存中没有view,则返回null;
a. 第三种情况,这个最简单:
一开始,listview稳定后,显示N个,此时mScrapView中是没有缓存view的,当我们向上滚动一小段距离(第一个此时仍显示部分),新的view将会显示,此时listview会调用Adapter.getView,但是缓存中没有,因此convertView是null,所以,我们得分配一块内存来创建新的convertView;
b. 第二种情况:
在a中,我们继续向上滚动,直接第一个view完全移出屏幕(假设没有新的item),此时,第一个view就会被detach,并被加入到mScrapView中;然后,我们还继续向上滚动,直接后面又将要显示新的item view时,此时,系统会从mScrapView中找position对应的View,显然,是找不到的,则将从mScrapView中,取最后一个缓存的view传递给convertView;
c. 第一种情况:
紧接着在b中,第一个被完全移出,加入到mScrapView中,且没有新增的item到listview中,此时,缓存中就只有第一个view;然后,我此时向下滑动,则之前的第一个item,将被显示出来,此时,从缓存中查找position对应的view有没有,当然,肯定是找到了,就直接返回了。
在项目的工程实践中出现了第二种情况,我想是因为我在request之初将typelist置空,这时候会执行setadapter,但是这时候gettypecount函数返回为零,scrapview只会存一个scrap(即滑出列表的titleview),但这时应该生产一个footview,当然就会转型错误了。
//void scrapActiveViews()一个将所有ActivieView全部转移到ScrapView中的方法,暂时没看到在哪用