前言:
定义:适配器模式是把一个类的接口变换成客户端所期待的另一种接口,从而使得原本因接口不匹配而无法一起工作的两个类能协同工作。
适配器是将两个不兼容的类融合在一起,它有点像粘合剂,将不同的东西通过一个转换使得它们能够协作起来.
Android源码的适配器模式
1.首先看ListView的父类,AbsListView。
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
ListAdapter mAdapter;
/**
* 关联到 Window时,通过 Adapter来获取 Item View 的数量、布局、数据等
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
treeObserver.addOnTouchModeChangeListener(this);
if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
treeObserver.addOnGlobalLayoutListener(this);
}
/**
* 给设配器注册一个观察者
*/
if (mAdapter != null && mDataSetObserver == null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
// Data may have changed while we were detached. Refresh.
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
}
}
/**
* 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) {
for (int i = 0; i < childCount; i++) {
getChildAt(i).forceLayout();
}
mRecycler.markChildrenDirty();
}
//布局 Child View
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 定义了集合视图的逻辑框架,比如 Adapter模式的应用、复用 Item View 的逻辑、布局自视图的逻辑等。
2.ListView 覆写了的 layoutChildren。
ListView 覆写了 AbsListView 中的 layoutChildren。在 layoutChildren 中根据布局模式来布局 Item View,例如有从上而下,也有从下而上开始布局的(qq聊天的气泡布局,最新的消息到窗口的最底部)。我们来看看这两种实现
- 从上而下填充 Item View(只是其中的一种方式)
/**
* Fills the list from pos down to the end of the list view.
*
* @param pos The first position to put in the list
*
* @param nextTop The location where the top of the item associated with pos
* should be drawn
*
* @return The view that is currently selected, if it happens to be in the
* range that we draw.
*/
private View fillDown(int pos, int nextTop) {
View selectedView = null;
int end = (mBottom - mTop);
if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
end -= mListPadding.bottom;
}
while (nextTop < end && pos < mItemCount) {
// is this the selected item?
boolean selected = pos == mSelectedPosition;
View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
nextTop = child.getBottom() + mDividerHeight;
if (selected) {
selectedView = child;
}
pos++;
}
setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
return selectedView;
}
总结:
ListView 等集合控件通过 Adapter来获取 Item View 的数量、布局、数据等,在这里尤为重要的就是 View类型的对象,也就是 Item View.由于它返回的是一个 View抽象,而千变万化的 UI视图都是 View 的子类,通过依赖抽象原则和 Adapter 模式就将 Item View 的变化隔离了,保证了 AbsListView 类族的高度可定制化。在获取到 View之后,将这些 View 通过特定的布局方式设置到对应的位置,再加上 Item View 的复用机制,整个 ListView就运转起来了。