在listview的重用view的原理是:将可视的view和非可视的view保存在两个数据结构中,分别指mActivityView和scrapView中,
mActivityView指的是,当前屏幕上显示的显示的View。
scrapView是指,屏幕上不显示的View,所有mActivityView都会转换成scrapView。
重用是把scrapView 传给Adapter.getView , 参数convertView 不为空就是从scrapView拿出的View。
public View getView(int position, View convertView,ViewGroup parent)
从代码分析可知,在listview中当有多种viewtype的时候,在adapter中继承设置getItemViewType方法可以更有效率
ListView(extends AbsListView)
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
boolean selected) {
View child;
if (!mDataChanged) {// 数据没有更新时,使用以前的view
// Try to use an exsiting view for this position
child = mRecycler.getActiveView(position);
if (child != null) {
// Found it -- we're using an existing child
// This just needs to be positioned
setupChild(child, position, y, flow, childrenLeft, selected, true);
return child;
}
}
// Make a new view for this position, or convert an unused view if possible
child = obtainView(position);
// This needs to be positioned and measured
setupChild(child, position, y, flow, childrenLeft, selected, false);
return child;
}
View obtainView(int position) {
View scrapView;
// 查看回收站中是否有废弃无用的View,如果有,则使用它,无需New View。
scrapView = mRecycler.getScrapView(position);
View child;
if (scrapView != null) { //此时说明可以从回收站中重新使用scrapView。
child = mAdapter.getView(position, scrapView, this);
if (child != scrapView) { // 没有使用处于回收站中的scrapView,还是New了一个View
mRecycler.addScrapView(scrapView); // scrapView 仍然放入回收站
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
}
} else {
child = mAdapter.getView(position, null, this);
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
}
return child;
}
void trackMotionScroll(int deltaY, int incrementalDeltaY) {
// 滚动时,不在可见范围内的item都放入回收站
if (down) {
final int top = listPadding.top - incrementalDeltaY;
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getBottom() >= top) {
break;
} else {
count++;
int position = firstPosition + i;
if (position >= headerViewsCount && position < footerViewsStart) {
mRecycler.addScrapView(child); //放入回收站
}
}
}
} else {
final int bottom = getHeight() - listPadding.bottom - incrementalDeltaY;
for (int i = childCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
if (child.getTop() <= bottom) {
break;
} else {
start = i;
count++;
int position = firstPosition + i;
if (position >= headerViewsCount && position < footerViewsStart) {
mRecycler.addScrapView(child); //放入回收站
}
}
}
}
}
}
RecycleBin有2种方式存储View,ActiveViews和ScrapViews。ActiveViews是指显示在屏幕上的View,在一个Layout的开始部分。
通过建设, ActiveViews是显示当前信息。
在布局的最后,所有的ActiveViews将为ScrapViews。
ScrapViews的意思是,旧的View,可以使用adapter避免不必要的View
class RecycleBin {
private RecyclerListener mRecyclerListener;
/**
第一个mActiveViews中的第一个View在ListView中的位置。
*/
private int mFirstActivePosition;
/**
屏幕中可见的View,在mActiveViews 中的View,最后都会到mScrapViews中。mActiveViews中存储着连续的可见的View,从第一个View,到最后一个可见的View
*/
private View[] mActiveViews = new View[0];
/**
存储在mScrapViews的View,将会被adapter 利用,作为convert view
*/
private ArrayList<View>[] mScrapViews;
private int mViewTypeCount;
private ArrayList<View> mCurrentScrap;
private ArrayList<View> mSkippedScrap;
private SparseArray<View> mTransientStateViews;
public void setViewTypeCount(int viewTypeCount) {
if (viewTypeCount < 1) {
throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
}
//noinspection unchecked
ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
for (int i = 0; i < viewTypeCount; i++) {
scrapViews[i] = new ArrayList<View>();
}
mViewTypeCount = viewTypeCount;
mCurrentScrap = scrapViews[0];
mScrapViews = scrapViews;
}