AdapterView是所有使用到Adapter的父类,AdapterView显示的列表项内容由Adapter提供
AdapterView派生三个子类:
AbsListView、AbsSpinner、AdapterViewAnimator
(1)ListView:列表
(2)Spinner:下拉选择列表,给用户提供选择
(3)Gallery:画廊,水平滚动的列表
(4)GridView:网格图
Adapter
作为View和数据之间的桥梁
可以把AdapterView当做View层,Adapter为Control层,数据则是Model层。
绘制流程
作为ViewGroup的子类,AdapterView仅仅重写了onLayout方法,返回一个 mLayoutHeight,其余的交由子类实现。
那么,看一下其中最常用的AbsListView的实现
//子类不可重写该方法
/** * Subclasses should NOT override this method but * {@link #layoutChildren()} instead. */
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mInLayout =true;
final int childCount = getChildCount();
if (changed) {
//遍历所有子view,做 forceLayout()
for (int i =0; i < childCount; i++) {
getChildAt(i).forceLayout();
}
mRecycler.markChildrenDirty();
}
//触发子类需要重写的方法,
layoutChildren();
mInLayout =false;
mOverscrollMax = (b - t) /OVERSCROLL_LIMIT_DIVISOR;
// TODO: Move somewhere sane. This doesn't belong in onLayout().
if (mFastScroll !=null) {
mFastScroll.onItemCountChanged(getChildCount(), mItemCount);
}
}
AbsListView的 onMeasure 仅在 TRANSCRIPT_MODE_NORMAL 模式下做了一次mForceTranscriptScroll支持,真正的方法实现还是交于了实现类
mRecycler是ABsList中的类RecycleBin,存储了View的两级缓存
activeViews:是一个一维数组,包含当前屏幕展示的所有View
scrapViews:二维数组,第二维长度对应ViewTypeCount的返回值,下标与Adapter.getItemViewType对应
public void markChildrenDirty() {
//只有一种ViewType时
if (mViewTypeCount ==1) {
final ArrayList scrap =mCurrentScrap;
final int scrapCount = scrap.size();
for (int i =0; i < scrapCount; i++) {
scrap.get(i).forceLayout();
}
}else {
//将二维 mScrapViews 所有的View刷新一遍
final int typeCount =mViewTypeCount;
for (int i =0; i < typeCount; i++) {
final ArrayList scrap =mScrapViews[i];
final int scrapCount = scrap.size();
for (int j =0; j < scrapCount; j++) {
scrap.get(j).forceLayout();
}
}
}
***
}
}
ListView 的layoutChildren方法流程较为复杂,这里介绍了与缓存的修改流程。
1.如果dataChanged则执行2,否则执行3
2.从mFirstPosition开始,依次将childCount个子View执行recycleBin.addScrapView(getChildAt(i), firstPosition+i);
3.从mFirstPosition开始,将所有的childView(非HEADER_OR_FOOTER)添加入RecycleBin的activeViews中,同时修改其param.scrappedFromPosition为缓存时候的position
4.执行detachAllViewsFromParent,将所有子View与其parent设置为null
5.对RecycleBin的mSkippedScrap中所有View调用removeDetachedView
6.根据传入的mLayoutMode,重新进行fill,同时触发scrapActiveViews
7.更新HEADER和FOOTER
在具体的fill过程中,触发makeAndAddView()
1.如果dataChanged则执行2,否则执行4
2.如果mAdapterHasStableIds,则去mTransientStateViewsById获取,否则从mTransientStateViews获取View
3.如果步骤2获取为null,根据ViewTypeCount分别从mCurrentScrap,mScrapViews中获取scrapView,并且调用mAdapter.getView(position, scrapView, this)
4.从recycleBin.activeViews中获取View
5.重新对获取的Viewz做setupChild
缓存未命中
obtainView方法中,getScrapView会遍历每个Id或者position是否与之前设定的 相同(id == params.itemId 或者params.scrappedFromPosition ==position),否则将返回scrapViews的最后一个View