1、 觀察者模式與監聽器機制
1.1 觀察者模式
1.2 監聽器(Listener)機制
代碼的基本框架:
* 被監控着
package com.wonders.group;
import java.util.Collection;
public class ModelTie {
private Collection<Object> dataSet;
public interface DataSetSupervioer {
public void onChange();
}
private DataSetSupervioer dataSetChangeListener;
public void setDataSetChangeListener(DataSetSupervioer dataSetChangeListener) {
this.dataSetChangeListener = dataSetChangeListener;
}
public void notifyDataSetChange() {
if (null != dataSetChangeListener) {
dataSetChangeListener.onChange();
}
}
public Collection<Object> getDataSet() {
return dataSet;
}
public ModelTie setDataSet(Collection<Object> dataSet) {
this.dataSet = dataSet;
this.notifyDataSetChange(); // 數據設置完畢要通知監聽器進行更新操作
return this;
}
}
* 監控者
package com.wonders.group;
import java.util.Collection;
import java.util.Iterator;
import com.wonders.group.ModelTie.DataSetSupervioer;
public class PresentationTie {
private ModelTie model;
public PresentationTie() {
super();
// 添加監聽器
model.setDataSetChangeListener(new DataSetSupervioer() {
public void onChange() {
// 填寫一些前置操作,如更新數據
DisplayModel(); // 重新繪制
// 填寫一些后置操作,如更新狀態
}
});
}
public void DisplayModel() {
Collection<Object> collection = model.getDataSet();
if (collection != null) {
for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
System.out.println(((Object) iterator.next()).toString());
// 其他等等操作
}
}
}
public ModelTie getModel() {
return model;
}
public void setModel(ModelTie model) {
this.model = model;
}
}
2、 ArrayAdapter的觀察者實現機制
以下僅羅列關鍵代碼:
public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
private boolean mNotifyOnChange = true;
/**
* Adds the specified object at the end of the array.
*/
public void add(T object) {
if (mOriginalValues != null) {
synchronized (mLock) {
mOriginalValues.add(object);
if (mNotifyOnChange) notifyDataSetChanged();
}
} else {
mObjects.add(object);
if (mNotifyOnChange) notifyDataSetChanged();
}
}
/**
* Inserts the specified object at the specified index in the array.
*/
public void insert(T object, int index) {
if (mOriginalValues != null) {
synchronized (mLock) {
mOriginalValues.add(index, object);
if (mNotifyOnChange) notifyDataSetChanged();
}
} else {
mObjects.add(index, object);
if (mNotifyOnChange) notifyDataSetChanged();
}
}
/**
* Removes the specified object from the array.
*/
public void remove(T object) {
if (mOriginalValues != null) {
synchronized (mLock) {
mOriginalValues.remove(object);
}
} else {
mObjects.remove(object);
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Remove all elements from the list.
*/
public void clear() {
if (mOriginalValues != null) {
synchronized (mLock) {
mOriginalValues.clear();
}
} else {
mObjects.clear();
}
if (mNotifyOnChange) notifyDataSetChanged();
}
/**
* Sorts the content of this adapter using the specified comparator.
*/
public void sort(Comparator<? super T> comparator) {
Collections.sort(mObjects, comparator);
if (mNotifyOnChange) notifyDataSetChanged();
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged(); // 關鍵代碼,這個notifyDataSetChanged()是從父類BaseAdapter繼承過來的,所以看看在父類中它干了些什么
mNotifyOnChange = true;
}
}
/**
* Common base class of common implementation for an {@link Adapter} that can be
* used in both {@link ListView} (by implementing the specialized
* {@link ListAdapter} interface} and {@link Spinner} (by implementing the
* specialized {@link SpinnerAdapter} interface.
*/
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
|
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached View that the underlying data has been changed
* and it should refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged(); // 關鍵代碼:說明調的是成員變量mDataSetObservable的方法,所以進入DataSetObservable看看具體是如何操作的
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
}
package android.database;
/**
* A specialization of Observable for DataSetObserver that provides methods for
* invoking the various callback methods of DataSetObserver.
*/
public class DataSetObservable extends Observable<DataSetObserver> {
/**
* Invokes onChanged on each observer. Called when the data set being observed has
* changed, and which when read contains the new state of the data.
*/
public void notifyChanged() {
synchronized(mObservers) {
for (DataSetObserver observer : mObservers) { // 這里的mObservers是哪來的呢?繼續追蹤,但首先可以判斷是來自Observable<DataSetObserver>的。進入看看
observer.onChanged();
}
}
}
/**
* Invokes onInvalidated on each observer. Called when the data set being monitored
* has changed such that it is no longer valid.
*/
public void notifyInvalidated() {
synchronized (mObservers) {
for (DataSetObserver observer : mObservers) {
observer.onInvalidated();
}
}
}
}
public abstract class Observable<T> {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected final ArrayList<T> mObservers = new ArrayList<T>();
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}
public void unregisterObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
int index = mObservers.indexOf(observer);
if (index == -1) {
throw new IllegalStateException("Observer " + observer + " was not registered.");
}
mObservers.remove(index);
}
}
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}
對於DataSetObserver基類,我們也給出代碼:
public abstract class DataSetObserver {
public void onChanged() {}
public void onInvalidated() {}
}
綜合起來分析就是,ArrayAdapter使自己具備被觀察的能力的方法是,ArrayAdapter內部有一個private final DataSetObservable mDataSetObservable = new DataSetObservable()的變量,這個變量一方面維護着一個保存觀察者的數據結構,另一方面提供registerDataSetObserver(DataSetObserver observer)和unregisterDataSetObserver(DataSetObserver observer)來管理觀察自己的對象;而當ArrayAdapter綁定數的據發生變化時,它會調用內部的notifyDataSetChanged()方法,但這個方法最終是調用mDataSetObservable的notifyChanged()方法。在該方法里,該方法會逐一審視有哪些觀察者在觀察我,然后調用觀察者的觀察方法onChanged()。
3、 ListView觀察ArrayAdapter的數據集的機制
通過以上分析可以知道,ListView要實現觀察ArrayAdapter,需要將自己注冊到ArrayAdapter的DataSetObservable mDataSetObservable里去,注冊的方法是調用ArrayAdapter的registerDataSetObserver(DataSetObserver observer)方法。
那ListView是如何將自己注冊上去的呢?具體過程如下:
public class ListView extends AbsListView {
/**
* Sets the data behind this ListView.
*
* The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},
* depending on the ListView features currently in use. For instance, adding
* headers and/or footers will cause the adapter to be wrapped.
*
* @param adapter The ListAdapter which is responsible for maintaining the
* data backing this list and for producing a view to represent an
* item in that data set.
*/
@Override
public void setAdapter(ListAdapter adapter) {
if (null != mAdapter) {
mAdapter.unregisterDataSetObserver(mDataSetObserver); // 關鍵的成員變量,繼承自AbsListView,等下去看看AbsListView關於mDataSetObserver的內容
}
resetList();
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver); // 在這里進行注冊,注冊為數據集的觀察員
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
int position;
if (mStackFromBottom) {
position = lookForSelectablePosition(mItemCount - 1, false);
} else {
position = lookForSelectablePosition(0, true);
}
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
if (mChoiceMode != CHOICE_MODE_NONE &&
mAdapter.hasStableIds() &&
mCheckedIdStates == null) {
mCheckedIdStates = new LongSparseArray<Boolean>();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
if (mCheckStates != null) {
mCheckStates.clear();
}
if (mCheckedIdStates != null) {
mCheckedIdStates.clear();
}
requestLayout();
}
}
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener {
/**
* Should be used by subclasses to listen to changes in the dataset
*/
AdapterDataSetObserver mDataSetObserver; // mDataSetObserver就是在這里定義的。那我們再看看AdapterDataSetObserver是什么類型的數據,看看當數據發生變化的時候,該類會進行什么樣的動作。
/**
* The adapter containing the data to be displayed by this view
*/
ListAdapter mAdapter;
}
值得注意的是,AdapterDataSetObserver是AdapterView里的一個內部類(http://www.androidjavadoc.com/1.1_r1_src/android/widget/class-use/AdapterView.AdapterDataSetObserver.html ),具體我們查看下代碼:
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout(); // 這里是關鍵:這就是為什么數據發生了變化,視圖可以隨之變換的原因,因為它會調用框架,來進行重新繪制。最終調用的代碼看緊接着的代碼
}
@Override
public void onInvalidated() {
mDataChanged = true;
if (AdapterView.this.getAdapter().hasStableIds()) {
// Remember the current state for the case where our hosting activity is being
// stopped and later restarted
mInstanceState = AdapterView.this.onSaveInstanceState();
}
// Data is invalid so we should reset our state
mOldItemCount = mItemCount;
mItemCount = 0;
mSelectedPosition = INVALID_POSITION;
mSelectedRowId = INVALID_ROW_ID;
mNextSelectedPosition = INVALID_POSITION;
mNextSelectedRowId = INVALID_ROW_ID;
mNeedSync = false;
checkSelectionChanged();
checkFocus();
requestLayout();
}
public void clearSavedState() {
mInstanceState = null;
}
}
最終調用的代碼(from View.class)
/**
* Call this when something has changed which has invalidated the
* layout of this view. This will schedule a layout pass of the view
* tree.
*/
public void requestLayout() {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
}
mPrivateFlags |= FORCE_LAYOUT;
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}