前言:
定義:適配器模式是把一個(gè)類的接口變換成客戶端所期待的另一種接口,從而使得原本因接口不匹配而無法一起工作的兩個(gè)類能協(xié)同工作。
適配器是將兩個(gè)不兼容的類融合在一起,它有點(diǎn)像粘合劑,將不同的東西通過一個(gè)轉(zhuǎn)換使得它們能夠協(xié)作起來.
Android源碼的適配器模式
1.首先看ListView的父類,AbsListView。
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
ListAdapter mAdapter;
/**
* 關(guān)聯(lián)到 Window時(shí),通過 Adapter來獲取 Item View 的數(shù)量、布局、數(shù)據(jù)等
*/
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final ViewTreeObserver treeObserver = getViewTreeObserver();
treeObserver.addOnTouchModeChangeListener(this);
if (mTextFilterEnabled && mPopup != null && !mGlobalLayoutListenerAddedFilter) {
treeObserver.addOnGlobalLayoutListener(this);
}
/**
* 給設(shè)配器注冊(cè)一個(gè)觀察者
*/
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模式的應(yīng)用、復(fù)用 Item View 的邏輯、布局自視圖的邏輯等。
2.ListView 覆寫了的 layoutChildren。
ListView 覆寫了 AbsListView 中的 layoutChildren。在 layoutChildren 中根據(jù)布局模式來布局 Item View,例如有從上而下,也有從下而上開始布局的(qq聊天的氣泡布局,最新的消息到窗口的最底部)。我們來看看這兩種實(shí)現(xiàn)
- 從上而下填充 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;
}
總結(jié):
ListView 等集合控件通過 Adapter來獲取 Item View 的數(shù)量、布局、數(shù)據(jù)等,在這里尤為重要的就是 View類型的對(duì)象,也就是 Item View.由于它返回的是一個(gè) View抽象,而千變?nèi)f化的 UI視圖都是 View 的子類,通過依賴抽象原則和 Adapter 模式就將 Item View 的變化隔離了,保證了 AbsListView 類族的高度可定制化。在獲取到 View之后,將這些 View 通過特定的布局方式設(shè)置到對(duì)應(yīng)的位置,再加上 Item View 的復(fù)用機(jī)制,整個(gè) ListView就運(yùn)轉(zhuǎn)起來了。