您的位置:首页 > 移动开发 > Android开发

android ListView中view的复用源码分析

2014-08-19 13:08 323 查看
下面简要分析android中BaseAdapter的getView()方法中convertView的来源(API19):

ListView一定在用户卷动列表的时候调用了adapter的getView()方法来获取要显示的新的项目的view对象。

然而ListView类的源代码中没有这个调用,所以应当是在其父类AbsListView中调用过,

我们在AbsListView类中查找adapter的getView()方法的调用作为追踪的起点:

1 AbsListView的obtainView()方法

//该方法调用了adapter的getView()方法

View obtainView(int position, boolean[] isScrap) {

........................

//scrapView是从mRecycler中取出的View对象

View scrapView;

scrapView =mRecycler.getTransientStateView(position);

if (scrapView == null) {

//从recycler中取出scrapView对象用于复用

scrapView = mRecycler.getScrapView(position);

}

View child;

//如果recycler中有可用的scrapView,就将scrapView传给adapter的getView()方法去复用

if (scrapView != null) {

//调用adapter的getView()方法,注意,scrapView就是getView()方法传入的形参convertView

child =mAdapter.getView(position, scrapView, this);

.........................

//如果adapter的getView()方法返回的View不是刚才传入的scrapView

//说明用户没有复用scrapView,它被重新放回到mRecylcler中

if (child != scrapView) {

mRecycler.addScrapView(scrapView, position);

...........................

}

}

//如果recycler中没有任何view可以拿出来传给adapter的getView()方法去复用,那就传null

else {

child = mAdapter.getView(position, null, this);

.......................

}

return child;

}

上面的源代码明确表示,用于复用的scrapView是调用mRecycler的getScrapView()方法得到的

而且不用的scrapView是调用mRecycler的addScrapView()方法放回mRecycler的

所以我们来看RecycleBin类和它的getScrapView()方法:

2 RecycleBin和它的getScrapView()方法

//上文中的mRecycler是RecycleBin类的一个对象

final RecycleBin mRecycler = new RecycleBin();

class RecycleBin{

..................

/** 原版注释:

* Views that were on screen at thestart of layout. This array is populated at the start of

* layout, and at the end of layout allview in mActiveViews are moved to mScrapViews.

* Views in mActiveViews represent acontiguous range of Views, with position of the first

* view store in mFirstActivePosition.

*/

/**原版注释的翻译:

* mActiveViews:

*布局生成伊始就显示在屏幕上的Views.这个数组在布局生成时就初始化,

* 最终所有在mActiveViews数组中的View都会被移动到mScrapViews。

* /

private View[]mActiveViews = new View[0];

/** 原版注释:

* Unsorted views that can be used by the adapter as a convert view.

*/

/** 原版注释的翻译:

* mScrapViews:

* 未排序的views,这些view可以被adapter用作复用

*/

privateArrayList<View>[] mScrapViews;

.....................................

/** 原版注释:

* @return A view from the ScrapViews collection. These are unordered.

*/

/** 原版注释的翻译:

* 从ScarpViews集合中返回一个View。返回的View是无序的。

*/

View getScrapView(int position) {

if (mViewTypeCount == 1) {

return retrieveFromScrap(mCurrentScrap, position);

} else {

int whichScrap =mAdapter.getItemViewType(position);

if (whichScrap >= 0&& whichScrap < mScrapViews.length) {

return retrieveFromScrap(mScrapViews[whichScrap],position);

}

}

return null;

}

..............................

}

看到这,我们发现RecycleBin类的getScrapView()方法实际上调用的是retrieveFromScrap()方法来获得ScrapView

而这个方法不是定义在RecycleBin类中的,是定义在AbsListView类中的一个静态方法:

3 AbsListView的retrieveFromScrap()方法

//RecycleBin的getScrapView()方法将RecycleBin类中的存储scrapViews的ArrayList传给下面的方法

//retrieveFromScrap()方法返回一个View给getScrapView()方法,进而传给adapter的getView()方法作为复用的view

static View retrieveFromScrap(ArrayList<View> scrapViews, intposition) {

int size = scrapViews.size();

//如果scrapViewarrayList中存储有scrapView

if (size > 0) {

//遍历arrayList中的所有scrapView

//去掉对应同一position的重复的scrapView

//如果刚好请求复用的position与scrapViewarrayList中某个scrapView的position相同

//则返回这个scrapView

for (int i=0; i<size; i++) {

View view = scrapViews.get(i);

if (((AbsListView.LayoutParams)view.getLayoutParams())

.scrappedFromPosition== position) {

scrapViews.remove(i);

return view;

}

}

//不巧没有对应同一position的scrapView,就将scrapViewarrayList的最后一项返回

-return scrapViews.remove(size 1);

//如果scrapViewarrayList中没有任何scrapView,返回null

} else {

return null;

}

}

4 总结

ListView中的RecycleBin内部类保存了一个View[]数组mActiveViews,用来保存屏幕上正在显示的所有View

还保存了一个ArrayList<View>集合mScrapViews,用来保存所有滑出屏幕等待复用的View。

当用户滑动屏幕时,ListView会从mActiveViews中将滑出屏幕的view加入mScrapViews

并从后者取出view传给adapter的getView()方法供其复用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: