• Android 设计模式 之 观察者模式


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

    有空我将把UML图补上。

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

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

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

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

    1. package android.database;  
    2.   
    3. /** 
    4.  * Receives call backs when a data set has been changed, or made invalid. The typically data sets 
    5.  * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s. 
    6.  * DataSetObserver must be implemented by objects which are added to a DataSetObservable. 
    7.  */  
    8. public abstract class DataSetObserver {  
    9.     /** 
    10.      * This method is called when the entire data set has changed, 
    11.      * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}. 
    12.      */  
    13.     public void onChanged() {  
    14.         // Do nothing  
    15.     }  
    16.   
    17.     /** 
    18.      * This method is called when the entire data becomes invalid, 
    19.      * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a 
    20.      * {@link Cursor}. 
    21.      */  
    22.     public void onInvalidated() {  
    23.         // Do nothing  
    24.     }  
    25. }  
    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

    1. package android.database;  
    2.   
    3. import java.util.ArrayList;  
    4.   
    5. /** 
    6.  * Provides methods for (un)registering arbitrary observers in an ArrayList. 
    7.  */  
    8. public abstract class Observable<T> {  
    9.     /** 
    10.      * The list of observers.  An observer can be in the list at most 
    11.      * once and will never be null. 
    12.      */  
    13.     protected final ArrayList<T> mObservers = new ArrayList<T>();  
    14.   
    15.     /** 
    16.      * Adds an observer to the list. The observer cannot be null and it must not already 
    17.      * be registered. 
    18.      * @param observer the observer to register 
    19.      * @throws IllegalArgumentException the observer is null 
    20.      * @throws IllegalStateException the observer is already registered 
    21.      */  
    22.     public void registerObserver(T observer) {  
    23.         if (observer == null) {  
    24.             throw new IllegalArgumentException("The observer is null.");  
    25.         }  
    26.         synchronized(mObservers) {  
    27.             if (mObservers.contains(observer)) {  
    28.                 throw new IllegalStateException("Observer " + observer + " is already registered.");  
    29.             }  
    30.             mObservers.add(observer);  
    31.         }  
    32.     }  
    33.   
    34.     /** 
    35.      * Removes a previously registered observer. The observer must not be null and it 
    36.      * must already have been registered. 
    37.      * @param observer the observer to unregister 
    38.      * @throws IllegalArgumentException the observer is null 
    39.      * @throws IllegalStateException the observer is not yet registered 
    40.      */  
    41.     public void unregisterObserver(T observer) {  
    42.         if (observer == null) {  
    43.             throw new IllegalArgumentException("The observer is null.");  
    44.         }  
    45.         synchronized(mObservers) {  
    46.             int index = mObservers.indexOf(observer);  
    47.             if (index == -1) {  
    48.                 throw new IllegalStateException("Observer " + observer + " was not registered.");  
    49.             }  
    50.             mObservers.remove(index);  
    51.         }  
    52.     }  
    53.       
    54.     /** 
    55.      * Remove all registered observer 
    56.      */  
    57.     public void unregisterAll() {  
    58.         synchronized(mObservers) {  
    59.             mObservers.clear();  
    60.         }          
    61.     }  
    62. }  
    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

    1. package android.database;  
    2.   
    3. /** 
    4.  * A specialization of Observable for DataSetObserver that provides methods for 
    5.  * invoking the various callback methods of DataSetObserver. 
    6.  */  
    7. public class DataSetObservable extends Observable<DataSetObserver> {  
    8.     /** 
    9.      * Invokes onChanged on each observer. Called when the data set being observed has 
    10.      * changed, and which when read contains the new state of the data. 
    11.      */  
    12.     public void notifyChanged() {  
    13.         synchronized(mObservers) {  
    14.             // since onChanged() is implemented by the app, it could do anything, including  
    15.             // removing itself from {@link mObservers} - and that could cause problems if  
    16.             // an iterator is used on the ArrayList {@link mObservers}.  
    17.             // to avoid such problems, just march thru the list in the reverse order.  
    18.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
    19.                 mObservers.get(i).onChanged();  
    20.             }  
    21.         }  
    22.     }  
    23.   
    24.     /** 
    25.      * Invokes onInvalidated on each observer. Called when the data set being monitored 
    26.      * has changed such that it is no longer valid. 
    27.      */  
    28.     public void notifyInvalidated() {  
    29.         synchronized (mObservers) {  
    30.             for (int i = mObservers.size() - 1; i >= 0; i--) {  
    31.                 mObservers.get(i).onInvalidated();  
    32.             }  
    33.         }  
    34.     }  
    35. }  
    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

    1. class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {  
    2.     @Override  
    3.     public void onChanged() {  
    4.         super.onChanged();  
    5.         if (mFastScroller != null) {  
    6.             mFastScroller.onSectionsChanged();  
    7.         }  
    8.     }  
    9.   
    10.     @Override  
    11.     public void onInvalidated() {  
    12.         super.onInvalidated();  
    13.         if (mFastScroller != null) {  
    14.             mFastScroller.onSectionsChanged();  
    15.         }  
    16.     }  
    17. }  
        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

    1. class AdapterDataSetObserver extends DataSetObserver {  
    2.   
    3.     private Parcelable mInstanceState = null;  
    4.   
    5.     @Override  
    6.     public void onChanged() {  
    7.         mDataChanged = true;  
    8.         mOldItemCount = mItemCount;  
    9.         mItemCount = getAdapter().getCount();  
    10.         if (DBG) {  
    11.             Xlog.d(TAG, "AdapterView onChanged: mOldItemCount = " + mOldItemCount  
    12.                     + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()  
    13.                     + ",AdapterView = " + AdapterView.this, new Throwable("onChanged"));  
    14.         }  
    15.   
    16.         // Detect the case where a cursor that was previously invalidated has  
    17.         // been repopulated with new data.  
    18.         if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null  
    19.                 && mOldItemCount == 0 && mItemCount > 0) {  
    20.             AdapterView.this.onRestoreInstanceState(mInstanceState);  
    21.             mInstanceState = null;  
    22.         } else {  
    23.             rememberSyncState();  
    24.         }  
    25.         checkFocus();  
    26.         requestLayout();  
    27.     }  
    28.   
    29.     @Override  
    30.     public void onInvalidated() {  
    31.         mDataChanged = true;  
    32.           
    33.         if (DBG) {  
    34.             Xlog.d(TAG, "AdapterView onInvalidated: mOldItemCount = " + mOldItemCount  
    35.                     + ",mItemCount = " + mItemCount + ",getAdapter() = " + getAdapter()  
    36.                     + ",AdapterView = " + AdapterView.this, new Throwable("onInvalidated"));  
    37.         }  
    38.   
    39.         if (AdapterView.this.getAdapter().hasStableIds()) {  
    40.             // Remember the current state for the case where our hosting activity is being  
    41.             // stopped and later restarted  
    42.             mInstanceState = AdapterView.this.onSaveInstanceState();  
    43.         }  
    44.   
    45.         // Data is invalid so we should reset our state  
    46.         mOldItemCount = mItemCount;  
    47.         mItemCount = 0;  
    48.         mSelectedPosition = INVALID_POSITION;  
    49.         mSelectedRowId = INVALID_ROW_ID;  
    50.         mNextSelectedPosition = INVALID_POSITION;  
    51.         mNextSelectedRowId = INVALID_ROW_ID;  
    52.         mNeedSync = false;  
    53.   
    54.         checkFocus();  
    55.         requestLayout();  
    56.     }  
    57.   
    58.     public void clearSavedState() {  
    59.         mInstanceState = null;  
    60.     }  
    61. }  
        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做了什么

    1. /** 
    2.  * Sets the data behind this ListView. 
    3.  * 
    4.  * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter}, 
    5.  * depending on the ListView features currently in use. For instance, adding 
    6.  * headers and/or footers will cause the adapter to be wrapped. 
    7.  * 
    8.  * @param adapter The ListAdapter which is responsible for maintaining the 
    9.  *        data backing this list and for producing a view to represent an 
    10.  *        item in that data set. 
    11.  * 
    12.  * @see #getAdapter()  
    13.  */  
    14. @Override  
    15. public void setAdapter(ListAdapter adapter) {  
    16.     if (mAdapter != null && mDataSetObserver != null) {  
    17.         mAdapter.unregisterDataSetObserver(mDataSetObserver);  
    18.     }  
    19.   
    20.     resetList();  
    21.     mRecycler.clear();  
    22.   
    23.     if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {  
    24.         mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);  
    25.     } else {  
    26.         mAdapter = adapter;  
    27.     }  
    28.   
    29.     mOldSelectedPosition = INVALID_POSITION;  
    30.     mOldSelectedRowId = INVALID_ROW_ID;  
    31.   
    32.     // AbsListView#setAdapter will update choice mode states.  
    33.     super.setAdapter(adapter);  
    34.   
    35.     if (mAdapter != null) {  
    36.         mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();  
    37.         mOldItemCount = mItemCount;  
    38.         mItemCount = mAdapter.getCount();  
    39.         checkFocus();  
    40.   
    41.         mDataSetObserver = new AdapterDataSetObserver();  
    42.         mAdapter.registerDataSetObserver(mDataSetObserver);  
    43.   
    44.         mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());  
    45.   
    46.         int position;  
    47.         if (mStackFromBottom) {  
    48.             position = lookForSelectablePosition(mItemCount - 1, false);  
    49.         } else {  
    50.             position = lookForSelectablePosition(0, true);  
    51.         }  
    52.         setSelectedPositionInt(position);  
    53.         setNextSelectedPositionInt(position);  
    54.   
    55.         if (mItemCount == 0) {  
    56.             // Nothing selected  
    57.             checkSelectionChanged();  
    58.         }  
    59.     } else {  
    60.         mAreAllItemsSelectable = true;  
    61.         checkFocus();  
    62.         // Nothing selected  
    63.         checkSelectionChanged();  
    64.     }  
    65.   
    66.     requestLayout();  
    67. }  
        /**
         * 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行

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

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

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

  • 相关阅读:
    Decrease (Judge ver.)
    Raising Modulo Numbers
    最短Hamilton路径
    64位整数乘法
    递归系列——数组和对象的相关递归
    函数内容新增——函数表达式
    数据结构和算法(一)——栈
    (转)jQuery中append(),prepend()与after(),before()的区别
    微信端的user-Agent
    less知识点总结(二)
  • 原文地址:https://www.cnblogs.com/bigben0123/p/4488434.html
Copyright © 2020-2023  润新知