在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; }