• 设计模式15---Android 观察者模式(转载自:“http://blog.csdn.net/fangchongbory/article/details/7774044”)


    [java] view plain copy
     
     print?
    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.  * */  

    有空我将把UML图补上。

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

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

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

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

    [java] view plain copy
     
     print?
    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. }  

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

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

    [java] view plain copy
     
     print?
    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. }  

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

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

    [java] view plain copy
     
     print?
    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. }  

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

    源码路径:

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

    [java] view plain copy
     
     print?
    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. }  

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

    [java] view plain copy
     
     print?
    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. }  

    实例:

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

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

    我们来看看ListView做了什么

    [java] view plain copy
     
     print?
    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. }  

    注意下面3行

    [java] view plain copy
     
     print?
    1. mAdapter = adapter;  
    [java] view plain copy
     
     print?
    1. mDataSetObserver = new AdapterDataSetObserver();  
    2. mAdapter.registerDataSetObserver(mDataSetObserver);  

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

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

  • 相关阅读:
    Ubuntu的启动配置文件grub.cfg(menu.lst)设置指南zz
    Qt/E客户端服务期间通信数据串行化
    开源协议简介BSD、 Apache Licence、GPL、LGPL、MIT转载
    Qt/E服务器到客户端的消息传递
    解决 Windows 和 Ubuntu 时间不一致的问题转载
    Qt/E服务器客户端架构
    Qt/E中的键盘设备管理
    Qt/E服务器客户端的通信机制
    解决 ssh 登录慢 转载
    c# 扩展方法奇思妙用变态篇一:由 Fibonacci 数列引出 “委托扩展” 及 “递推递归委托”
  • 原文地址:https://www.cnblogs.com/linghu-java/p/5889417.html
Copyright © 2020-2023  润新知