博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android中的所谓观察者模式
阅读量:6702 次
发布时间:2019-06-25

本文共 10222 字,大约阅读时间需要 34 分钟。

 生活中我们常认定某些人很有才,但什么是有才呢?明朝的王守仁曾这样解释:才,是所谓天理,应用到物上,便成了才。凡事凡物,只要掌握了所谓科学的方法,并能灵活运用,那么你也可以成为一个有才的人。

    观察者模式是软件设计都会运用到的一种模式,无论何种预言,由于本人是android猿类,所以本篇仅探讨android中的观察者模式,为了详致地阐述这一模式,本文分为三个部分:概念、简单实现、android中listview的具体实现。看完这三部分,相信您自己也能够驾轻就熟地在自己的软件中编写观察者模式了。

   每逢花晨月夕,便有丝竹管弦之兴,美文就要来袭了:)

   一、概念

  •    定义 观察者模式是由一个发送者(发送者是笔者自己的称呼,觉较之被观察者贴切得多)和一个观察者构成的、发送者在状态改变时(用户操作、程序主动改变等)主动通知所有观察者作相应的刷新。
  •    作用 面向对象的设计原则之一就是特定的对象干特定的事,比如眼睛对象和大脑对象 ,眼睛只需负责看,将看到的信息传给大脑,大脑只负责根据 接收到的信息作出对应的反应。观察者模式提供了良好的解耦。
  •    理论实现 观察者模式定义了对象之间一对多的的依赖关系,以便一个对象的状态发生改变时,所有依赖于他的对象都能够得到通知,并自动刷新。ps:这句话是复制的,如果你看得似是而非,请带着疑问看完简单实现部分就明白了。
  •    成员介绍 观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。                 被观察者:被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者
  • 图示

    二、简单实现

     依照图示,上代码:首先是observer的接口类

 
/** * Created by 笑飞 on 2016/4/28. * 观察者,需要应用观察者模式时要实现此接口 */public interface Observer  {    void onUpdate();}
 

    其次是observer的实现类

 
/** * Created by 笑飞 on 2016/4/28. */public class ConcreteObserver implements Observer {   private String myOnlyAttr;    private int changeCount;    /*刷新自己*/    @Override    public void onUpdate() {        myOnlyAttr = "通知Observer刷新了:"+(changeCount++)+"次";    }    public String getMyOnlyAttr() {        return myOnlyAttr;    }}
 

  其次是subject的祖宗类

 
/** * Created by 笑飞 on 2016/4/28. * 发送者,需要应用观察者模式时的被观察者要继承此类 */public abstract class Subject {    /*将一个被观察者对象和多个观察者对象绑定起来*/ protected List
observers = new ArrayList<>(); /*添加观察者,我们可能需要各种各样的观察者*/ public void attachObserver(Observer observer){ if (null ==observer){ throw new NullPointerException(); } if (!observers.contains(observer)){ observers.add(observer); } } public void detachObserver(Observer observer){ if (null ==observer){ throw new NullPointerException(); } if (observers.contains(observer)){ observers.remove(observer); } } public abstract void notifyObserverUpdate();}
 

其次是subject的实现类:

* * Created by 笑飞 on 2016/4/28. * 实现了刷新方法 */public class ConcreteSubject extends Subject {    @Override    public void notifyObserverUpdate() {        for (Observer observer :observers){            observer.onUpdate();        }    }}
 

然后是activity的测试部分

 
public class MainActivity extends AppCompatActivity {    private ConcreteSubject subject;    private TextView textView;    ConcreteObserver observer;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        textView = (TextView) findViewById(R.id.text);        observer = new ConcreteObserver();        subject = new ConcreteSubject();        /*绑定观察者*/        subject.attachObserver(observer);    }    public void update(View v){        /*通知观察者刷新*/        subject.notifyObserverUpdate();        textView.setText(observer.getMyOnlyAttr());    }}
 

    在开始第三部分之前,我们要注意,如果把上面的observer换成listview,把subject换成adapter,是不是我们经常看到和用到的listview的用法?其实 listview内置了observer,而adpter中内置了subject,换言之,listview和adapter其实就是观察者与被观察者的“形象代言人”。

   好了,接下啦让我们以android中的经典ArrayAdapter来开始第三部分的分析吧!

   三、android中listview的具体实现

  • listview中的observer
 
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); // 在这里进行注册,注册为发送者adapter的观察者            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
(); } } else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } if (mCheckStates != null) { mCheckStates.clear(); } if (mCheckedIdStates != null) { mCheckedIdStates.clear(); } requestLayout();}}
 

     mDataSetObserver这个观察者在AbsListView中:

AdapterDataSetObserver mDataSetObserver; // mDataSetObserver就是在这里定义的。那我们再看看AdapterDataSetObserver是什么类型的数据,看看当数据发生变化的时候,该类会进行什么样的动作。

   接下来去AdapterView中,发现AdapterDataSetObserver是其一个内部类:

 
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;        }    }
 
  •     ArrayAdapter中的subject(发送者,google大神命名为Observable,较为贴切)

          在ArrayAdapter中:

 
@Override    public void notifyDataSetChanged() {        super.notifyDataSetChanged();   // 关键代码,这个notifyDataSetChanged()是从父类BaseAdapter继承过来的,所以看看在父类中它干了些什么        mNotifyOnChange = true;}
 

         然后在BaseAdapter中:

 
private final DataSetObservable mDataSetObservable = new DataSetObservable();     //这对方法用来注册或注销从属ArrayAdapter的观察者,从此以后,adapter就成了发送者(Observable)的代理人    public void registerDataSetObserver(DataSetObserver observer) {        mDataSetObservable.registerObserver(observer);    }    public void unregisterDataSetObserver(DataSetObserver observer) {        mDataSetObservable.unregisterObserver(observer);    }      public void notifyDataSetChanged() {
  mDataSetObservable.notifyChanged();  // 关键代码:说明调的是成员变量mDataSetObservable的方法,所以进入DataSetObservable看看具体是如何操作的 }
 
 

       接下来看发送者和发送者的祖宗,是不是很熟悉了?请自行与第二部分的发送者对应:

 
public class DataSetObservable extends Observable
{ /** * 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
的。进入看看 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
{ /** * The list of observers. An observer can be in the list at most * once and will never be null. */ protected final ArrayList
mObservers = new ArrayList
(); 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(); } }}
 

总结:观察者模式看起来很高大上,其实说白了就是一个类维护了另一个类的一个集合,并通过这个集合绑定解绑或调用另一个类的方法,只不过,在设计底层框架时候,利用了多态的特性抽象出了接口和抽象类,以便适用于各种场合。其实在做终端页面时候完全用不到,因为多态只能增加运行时开销。然而,设置一个庞大系统时候,这种设计模式在面向对象的编程语言,可谓不能不用的手段了。

 

转载地址:http://ctgoo.baihongyu.com/

你可能感兴趣的文章
mongodb安全权限设定
查看>>
glib 散列表
查看>>
javascript模拟C# Stringbuilder
查看>>
解析Linux系统关于用户权限、组
查看>>
Android 如何判断一个应用在运行
查看>>
分组背包题目
查看>>
获取GridView TemplateField的数据
查看>>
Ecshop的lbi库文件中嵌套调用另一个lbi库文件
查看>>
Spring XmlBeanFactory例子[转]
查看>>
delphi AfterScrol
查看>>
用c#读取并分析sql2005日志
查看>>
两味中药治疗肛痔
查看>>
口唇口腔紅肿案
查看>>
ZeroMQ接口函数之 :zmq_ctx_get - 得到环境上下文的属性
查看>>
JSP基本用法(二)隐含对象
查看>>
权力社会? 金钱社会? 透过现象看本质-让权力和金钱的力量沿着制度的河道流淌,才是社会稳定的基石...
查看>>
均值滤波
查看>>
正则匹配之邮箱的匹配
查看>>
中缀表达式值
查看>>
算法笔记_147:有向图欧拉回路判断应用(Java)
查看>>