深入理解自定义ListView
ListView
原理
他是一个系统的原生控件,用列表的形式来显示内容。如果内容过过有1000条左右,我们可以通过手势的上下滑动来查看数据。
ListView
也不是爆出OOM(out of memery
)错误。下面是类的继承机构我们给
ListView
装配数据的时候,要给他定义一个适配器Adapter
,为什么要定义呢?
我的理解是给ListView
一个通道,在和我们的数据之间建立一个连接,这样当ListView
需要展现什么的数据,什么样的布局的时候我们就可以通过自己定义的Aapter
中的getView(parament...)
方法来获取到我们要加入到ListView
的视图。-
RecycleBin机制,它是写在
AbsListView
中的一个内部类,所以所有继承自AbsListView
的子类,也就是ListView
和GridView
,都可以使用这个机制,
主要作用,通过一系列方法,实现View
的缓存机制,
fillActiveViews(...)
这个方法接收两个参数,第一个参数表示要存储的view
的数量,第二个参数表示ListView
中第一个可见元素的position
值。RecycleBin
当中使用mActiveViews
这个数组来存储View,调用这个方法后就会根据传入的参数来将ListView
中的指定元素存储到mActiveViews
数组当中。
getActiveView(...)
用于根据参数*position
获取mActiveViews
当中的View
。需要注意的是当View
一旦被获取以后,下次再获取同样的位置就将会是null
。所以mActiveView
不能重复利用.\。
addScrapView(...)
用于将一个废弃的View
缓存。当我们View
将要废掉以后(比如滚出屏幕)。那么就会调用这个方法进行缓存。RecycleBin当中使用mScrapViews
和mCurrentScrap
这两个List
来存储废弃View
。
getScrapView(...)
用于在mScrapViews
中末尾取出一个废弃View
,
setViewTypeCount()
我们都知道Adapter
当中可以重写一个getViewTypeCount()
来表示ListView
中有几种类型的数据项,而setViewTypeCount()
方法的作用就是为每种类型的数据项都单独启用一个RecycleBin缓存机制。实际上,getViewTypeCount()
方法通常情况下使用的并不是很多,所以我们只要知道RecycleBin当中有这样一个功能就行了.
- 如何绘制
View
.我们通过自定义Adapter
中重写getView()
,获取到要显示的View
,当我们装载到ListView
的时候,是通过onMeasure()
来测量大小。onLayout()
用于确定View的布局,onDraw
来绘制View
显示到界面上。但是ListView
不负责绘制,是由他的子元素进行绘制的。
5.滑动加载更多数据 ,ListView
有滑动的监听机制onTouchEvent()
来监听手势的滑动。因为滑动是通用的机制所以写在AbsListView
当中,所以GridView
也可以使用这个机制。
View obtainView(int position, boolean[] isScrap) {
isScrap[0] = false;
View scrapView;
scrapView = mRecycler.getScrapView(position);
View child;
if (scrapView != null) {
child = mAdapter.getView(position, scrapView, this);
if (child != scrapView) {
mRecycler.addScrapView(scrapView);
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
} else {
isScrap[0] = true;
dispatchFinishTemporaryDetach(child);
}
} else {
child = mAdapter.getView(position, null, this);
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
}
return child;
}
通过读取上面的代码我们可以理解到:如果RecycleBin对应mRecycler
中获mActiveView
储存当中末尾获取一个废弃的View
。
通过如下代码传递一个scrapView
child = mAdapter.getView(position, scrapView, this);
如果为null
的话。那么就会通过该段代码
child = mAdapter.getView(position, null, this);
可以看到mAdapter
就是我们自己定义的适配器。所以obtainView
类会通过不断回收废弃的Veiw
通过getView(...)
来获取数据,所以就不会爆出OOM错误了。因为在Listview
当中,通过RecycleBin
的机制不断回收,具体原理如下图
适配器的优化参考我自己写的
自定义适配器优化