`

转:Android设计模式之观察者模式

 
阅读更多

转自CSDN:http://blog.csdn.net/fangchongbory/article/details/7774044

Android 设计模式 之 观察者模式

/*
 * 观察者模式
 * 定义对象间的一种一个(Subject)对多(Observer)的依赖关系,当一个对象的状态发送改变时,所以依赖于
 * 它的对象都得到通知并被自动更新
 * 当然,MVC只是Observer模式的一个实例。Observer模式要解决的问题为:
 * 建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,
 * 依赖这个“一”的多也能够同步改变。最常见的一个例子就是:对同一组数据进行统计分析时候,
 * 我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。
 * 这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。
 * Observer模式就是解决了这一个问题。
 * 
 * 适用性:
 * 		1. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面
 * 		将这两者封装成独立的对象中以使它们可以各自独立的改变和服用
 * 
 * 		2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变
 * 
 * 		3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
 * 
 * 参与者:
 * 		1. Subject(目标)
 * 		目标知道它的观察者,可以有任意多个观察者观察同一个目标
 * 		提供注册和删除观察者对象的接口
 * 
 * 		2. Observer(观察者)
 * 		为那些在目标发生改变时需获得通知的对象定义个更新的接口
 * 
 * 		3. ConcreteSubject(具体目标)
 * 		将有关状态存入各ConcreteObserver对象
 * 		当它的状态发送改变时,向它的各个观察者发出通知
 * 
 * 		4. ConcreteObserver(具体观察者)
 * 		维护一个指向ConcreteObserver对象的引用
 * 		存储有关状态,这些状态应与目标的状态保持一致
 * 		实现Observer的更新接口是自身状态与目标的状态保持一致
 * 		
 * 
 * */

 

下面看看Android使用到的观察者模式.

观察者(DataSetObserver),目标(Observable<T>),具体目标(DataSetObserverable)

Observer(观察者)

DataSetObserver抽象2个方法,一个是观察数据改变的方法,一个是观察数据变成无效(或者不可用)时的方法。

源码路径:framework/base/core/java/android/database/DataSetObserver.java

package android.database;

/**
 * Receives call backs when a data set has been changed, or made invalid. The typically
 * data sets that are observed are {@link Cursor}s or {@link android.widget.Adapter}s.
 * DataSetObserver must be implemented by objects which are added to a
 * DataSetObservable.
 */
public abstract class DataSetObserver {
    /**
     * This method is called when the entire data set has changed,
     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
     */
    public void onChanged() {
        // Do nothing
    }

    /**
     * This method is called when the entire data becomes invalid,
     * most likely through a call to {@link Cursor#deactivate()}
     * or {@link Cursor#close()} on a {@link Cursor}.
     */
    public void onInvalidated() {
        // Do nothing
    }
}

 

Subject(目标)

Observable<T>是一个泛型的抽象类,主要功能是注册和撤销observer。

源码路径:framework/base/core/java/android/database/Observable.java

package android.database;

import java.util.ArrayList;

/**
 * Provides methods for (un)registering arbitrary observers in an ArrayList.
 */
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>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must
     * not already be registered.
     * @param observer the observer to register
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is already registered
     */
    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);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    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);
        }
    }
    
    /**
     * Remove all registered observer
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }        
    }
}

 

ConcreateSubject(具体目标)

实现的方法同Oberver一样,只不过它是通知ArrayList<Observer>下的每个Oberver去执行各自的action。

源码路径:framework/base/core/java/android/database/DataSetObservable.java

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) {
            // since onChanged() is implemented by the app, it could do anything,
	    // including removing itself from {@link mObservers} - 
	    // and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).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 (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }
}

 

ConcreateObserver(具体观察者),具体观察者的任务是实实在在执行action的类,一般由开发者根据实际情况,自己实现。android也有实现的例子

源码路径:

framework/base/core/java/android/widget/AbsListView.java

    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }
    }

 

framework/base/core/java/android/widget/AdapterView.java

    class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();
            if (DBG) {
                Xlog.d(TAG, "AdapterView onChanged: mOldItemCount = " + mOldItemCount
                        + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()
                        + ",AdapterView = " + AdapterView.this, new Throwable("onChanged"));
            }

            // 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 (DBG) {
                Xlog.d(TAG, "AdapterView onInvalidated: mOldItemCount = " + mOldItemCount
                        + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()
                        + ",AdapterView = " + AdapterView.this, new Throwable("onInvalidated"));
            }

            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;

            checkFocus();
            requestLayout();
        }

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

 

实例:

型运用是大家熟悉的BaseAdapter,BaseAdapter关联了一个DataSetObservable对象,并实现registerDataSetObserver和unregisterDataSetObserver两个方法实现注册和撤销Observer,方法notifyDataSetChanged间接调用Observer的实现者的onChange()方法,以达到通知数据改变的作用。使用ListView和BaseAdapter组合时,当BaseAdapter的item改变时,我们经常会调用notifyDataSetChanged(),通知Listview刷新。

但是,但是,但是,我们从来没有调用BaseAdapter的registerDataSetObserver(DataSetObserver observer)注册Observer,那么Listview如何接收到通知,并执行刷新动作呢?

我们来看看ListView做了什么

    /**
     * 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.
     *
     * @see #getAdapter() 
     */
    @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(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;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        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();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }

 

注意下面3行

mAdapter = adapter;
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);

 

当我们setAdapter(ListAdapter adapter)时,BaseAdapter同时注册了AdapterDataSetObserver(),至于AdapterDataSetObserver是如何通知Listvew和每个子item刷新(invalidate)的,这里涉及到的内容已经超出文章的范围,具体请查看源码。

 

 

其实,Android用到DataSetObserver的地方很多,Cursor,WebView,Adapter,...非常之多。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics