android中的所谓观察者模式
2016-04-28 17:21
483 查看
生活中我们常认定某些人很有才,但什么是有才呢?明朝的王守仁曾这样解释:才,是所谓天理,应用到物上,便成了才。凡事凡物,只要掌握了所谓科学的方法,并能灵活运用,那么你也可以成为一个有才的人。
观察者模式是软件设计都会运用到的一种模式,无论何种预言,由于本人是android猿类,所以本篇仅探讨android中的观察者模式,为了详致地阐述这一模式,本文分为三个部分:概念、简单实现、android中listview的具体实现。看完这三部分,相信您自己也能够驾轻就熟地在自己的软件中编写观察者模式了。
每逢花晨月夕,便有丝竹管弦之兴,美文就要来袭了:)
一、概念
定义观察者模式是由一个发送者(发送者是笔者自己的称呼,觉较之被观察者贴切得多)和一个观察者构成的、发送者在状态改变时(用户操作、程序主动改变等)主动通知所有观察者作相应的刷新。
作用面向对象的设计原则之一就是特定的对象干特定的事,比如眼睛对象和大脑对象,眼睛只需负责看,将看到的信息传给大脑,大脑只负责根据接收到的信息作出对应的反应。观察者模式提供了良好的解耦。
理论实现观察者模式定义了对象之间一对多的的依赖关系,以便一个对象的状态发生改变时,所有依赖于他的对象都能够得到通知,并自动刷新。ps:这句话是复制的,如果你看得似是而非,请带着疑问看完简单实现部分就明白了。
成员介绍观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。被观察者:被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者
图示
二、简单实现
依照图示,上代码:首先是observer的接口类
其次是observer的实现类
其次是subject的祖宗类
其次是subject的实现类:
然后是activity的测试部分
在开始第三部分之前,我们要注意,如果把上面的observer换成listview,把subject换成adapter,是不是我们经常看到和用到的listview的用法?其实listview内置了observer,而adpter中内置了subject,换言之,listview和adapter其实就是观察者与被观察者的“形象代言人”。
好了,接下啦让我们以android中的经典ArrayAdapter来开始第三部分的分析吧!
三、android中listview的具体实现
listview中的observer
mDataSetObserver这个观察者在AbsListView中:
接下来去AdapterView中,发现AdapterDataSetObserver是其一个内部类:
ArrayAdapter中的subject(发送者,google大神命名为Observable,较为贴切)
在ArrayAdapter中:
然后在BaseAdapter中:
接下来看发送者和发送者的祖宗,是不是很熟悉了?请自行与第二部分的发送者对应:
总结:观察者模式看起来很高大上,其实说白了就是一个类维护了另一个类的一个集合,并通过这个集合绑定解绑或调用另一个类的方法,只不过,在设计底层框架时候,利用了多态的特性抽象出了接口和抽象类,以便适用于各种场合。其实在做终端页面时候完全用不到,因为多态只能增加运行时开销。然而,设置一个庞大系统时候,这种设计模式在面向对象的编程语言,可谓不能不用的手段了。
观察者模式是软件设计都会运用到的一种模式,无论何种预言,由于本人是android猿类,所以本篇仅探讨android中的观察者模式,为了详致地阐述这一模式,本文分为三个部分:概念、简单实现、android中listview的具体实现。看完这三部分,相信您自己也能够驾轻就熟地在自己的软件中编写观察者模式了。
每逢花晨月夕,便有丝竹管弦之兴,美文就要来袭了:)
一、概念
定义观察者模式是由一个发送者(发送者是笔者自己的称呼,觉较之被观察者贴切得多)和一个观察者构成的、发送者在状态改变时(用户操作、程序主动改变等)主动通知所有观察者作相应的刷新。
作用面向对象的设计原则之一就是特定的对象干特定的事,比如眼睛对象和大脑对象,眼睛只需负责看,将看到的信息传给大脑,大脑只负责根据接收到的信息作出对应的反应。观察者模式提供了良好的解耦。
理论实现观察者模式定义了对象之间一对多的的依赖关系,以便一个对象的状态发生改变时,所有依赖于他的对象都能够得到通知,并自动刷新。ps:这句话是复制的,如果你看得似是而非,请带着疑问看完简单实现部分就明白了。
成员介绍观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。被观察者:被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者
图示
二、简单实现
依照图示,上代码:首先是observer的接口类
/** *Createdby笑飞on2016/4/28. *观察者,需要应用观察者模式时要实现此接口 */ publicinterfaceObserver{ voidonUpdate(); }
其次是observer的实现类
/** *Createdby笑飞on2016/4/28. */ publicclassConcreteObserverimplementsObserver{ privateStringmyOnlyAttr; privateintchangeCount; /*刷新自己*/ @Override publicvoidonUpdate(){ myOnlyAttr="通知Observer刷新了:"+(changeCount++)+"次"; } publicStringgetMyOnlyAttr(){ returnmyOnlyAttr; } }
其次是subject的祖宗类
/** *Createdby笑飞on2016/4/28. *发送者,需要应用观察者模式时的发送者要继承此类 */ publicabstractclassSubject{ /*将一个被观察者对象和多个观察者对象绑定起来*/ protectedList<Observer>observers=newArrayList<>(); /*添加观察者,我们可能需要各种各样的观察者*/ publicvoidattachObserver(Observerobserver){ if(null==observer){ thrownewNullPointerException(); } if(!observers.contains(observer)){ observers.add(observer); } } publicvoiddetachObserver(Observerobserver){ if(null==observer){ thrownewNullPointerException(); } if(observers.contains(observer)){ observers.remove(observer); } } publicabstractvoidnotifyObserverUpdate(); }
其次是subject的实现类:
/** *Createdby笑飞on2016/4/28. *实现了刷新方法 */ publicclassConcreteSubjectextendsSubject{ @Override publicvoidnotifyObserverUpdate(){ for(Observerobserver:observers){ observer.onUpdate(); } } }
然后是activity的测试部分
publicclassMainActivityextendsAppCompatActivity{ privateConcreteSubjectsubject; privateTextViewtextView; ConcreteObserverobserver; @Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView=(TextView)findViewById(R.id.text); observer=newConcreteObserver(); subject=newConcreteSubject(); /*绑定观察者*/ subject.attachObserver(observer); } publicvoidupdate(Viewv){ /*通知观察者刷新*/ subject.notifyObserverUpdate(); textView.setText(observer.getMyOnlyAttr()); } }
在开始第三部分之前,我们要注意,如果把上面的observer换成listview,把subject换成adapter,是不是我们经常看到和用到的listview的用法?其实listview内置了observer,而adpter中内置了subject,换言之,listview和adapter其实就是观察者与被观察者的“形象代言人”。
好了,接下啦让我们以android中的经典ArrayAdapter来开始第三部分的分析吧!
三、android中listview的具体实现
listview中的observer
publicvoidsetAdapter(ListAdapteradapter){ if(null!=mAdapter){ mAdapter.unregisterDataSetObserver(mDataSetObserver);//关键的成员变量,继承自AbsListView,等下去看看AbsListView关于mDataSetObserver的内容 } resetList(); mRecycler.clear(); if(mHeaderViewInfos.size()>0||mFooterViewInfos.size()>0){ mAdapter=newHeaderViewListAdapter(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=newAdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);//在这里进行注册,注册为发送者adapter的观察者 mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); intposition; if(mStackFromBottom){ position=lookForSelectablePosition(mItemCount-1,false); }else{ position=lookForSelectablePosition(0,true); } setSelectedPositionInt(position); setNextSelectedPositionInt(position); if(mItemCount==0){ //Nothingselected checkSelectionChanged(); } if(mChoiceMode!=CHOICE_MODE_NONE&& mAdapter.hasStableIds()&& mCheckedIdStates==null){ mCheckedIdStates=newLongSparseArray<Boolean>(); } }else{ mAreAllItemsSelectable=true; checkFocus(); //Nothingselected checkSelectionChanged(); } if(mCheckStates!=null){ mCheckStates.clear(); } if(mCheckedIdStates!=null){ mCheckedIdStates.clear(); } requestLayout(); } }
mDataSetObserver这个观察者在AbsListView中:
AdapterDataSetObservermDataSetObserver;//mDataSetObserver就是在这里定义的。那我们再看看AdapterDataSetObserver是什么类型的数据,看看当数据发生变化的时候,该类会进行什么样的动作。
接下来去AdapterView中,发现AdapterDataSetObserver是其一个内部类:
classAdapterDataSetObserverextendsDataSetObserver{ privateParcelablemInstanceState=null; @Override publicvoidonChanged(){ mDataChanged=true; mOldItemCount=mItemCount; mItemCount=getAdapter().getCount(); //Detectthecasewhereacursorthatwaspreviouslyinvalidatedhas //beenrepopulatedwithnewdata. if(AdapterView.this.getAdapter().hasStableIds()&&mInstanceState!=null&&mOldItemCount==0&&mItemCount>0){ AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState=null; }else{ rememberSyncState(); } checkFocus(); requestLayout();//这里是关键:这就是为什么数据发生了变化,视图可以随之变换的原因,因为它会调用框架,来进行重新绘制。最终调用的代码看紧接着的代码 } @Override publicvoidonInvalidated(){ mDataChanged=true; if(AdapterView.this.getAdapter().hasStableIds()){ //Rememberthecurrentstateforthecasewhereourhostingactivityisbeing //stoppedandlaterrestarted mInstanceState=AdapterView.this.onSaveInstanceState(); } //Dataisinvalidsoweshouldresetourstate mOldItemCount=mItemCount; mItemCount=0; mSelectedPosition=INVALID_POSITION; mSelectedRowId=INVALID_ROW_ID; mNextSelectedPosition=INVALID_POSITION; mNextSelectedRowId=INVALID_ROW_ID; mNeedSync=false; checkSelectionChanged(); checkFocus(); requestLayout(); } publicvoidclearSavedState(){ mInstanceState=null; } }
ArrayAdapter中的subject(发送者,google大神命名为Observable,较为贴切)
在ArrayAdapter中:
@Override publicvoidnotifyDataSetChanged(){ super.notifyDataSetChanged();//关键代码,这个notifyDataSetChanged()是从父类BaseAdapter继承过来的,所以看看在父类中它干了些什么 mNotifyOnChange=true; }
然后在BaseAdapter中:
privatefinalDataSetObservablemDataSetObservable=newDataSetObservable(); //这对方法用来注册或注销从属ArrayAdapter的观察者,从此以后,adapter就成了发送者(Observable)的代理人 publicvoidregisterDataSetObserver(DataSetObserverobserver){ mDataSetObservable.registerObserver(observer); } publicvoidunregisterDataSetObserver(DataSetObserverobserver){ mDataSetObservable.unregisterObserver(observer); } publicvoidnotifyDataSetChanged(){ mDataSetObservable.notifyChanged();//关键代码:说明调的是成员变量mDataSetObservable的方法,所以进入DataSetObservable看看具体是如何操作的 }
接下来看发送者和发送者的祖宗,是不是很熟悉了?请自行与第二部分的发送者对应:
publicclassDataSetObservableextendsObservable<DataSetObserver>{
/**
*InvokesonChangedoneachobserver.Calledwhenthedatasetbeingobservedhas
*changed,andwhichwhenreadcontainsthenewstateofthedata.
*/
publicvoidnotifyChanged(){
synchronized(mObservers){
for(DataSetObserverobserver:mObservers){//这里的mObservers是哪来的呢?继续追踪,但首先可以判断是来自Observable<DataSetObserver>的。进入看看
observer.onChanged();
}
}
}
/**
*InvokesonInvalidatedoneachobserver.Calledwhenthedatasetbeingmonitored
*haschangedsuchthatitisnolongervalid.
*/
publicvoidnotifyInvalidated(){
synchronized(mObservers){
for(DataSetObserverobserver:mObservers){
observer.onInvalidated();
}
}
}
}
publicabstractclassObservable<T>{
/**
*Thelistofobservers.Anobservercanbeinthelistatmost
*onceandwillneverbenull.
*/
protectedfinalArrayList<T>mObservers=newArrayList<T>();
publicvoidregisterObserver(Tobserver){
if(observer==null){
thrownewIllegalArgumentException("Theobserverisnull.");
}
synchronized(mObservers){
if(mObservers.contains(observer)){
thrownewIllegalStateException("Observer"+observer+"isalreadyregistered.");
}
mObservers.add(observer);
}
}
publicvoidunregisterObserver(Tobserver){
if(observer==null){
thrownewIllegalArgumentException("Theobserverisnull.");
}
synchronized(mObservers){
intindex=mObservers.indexOf(observer);
if(index==-1){
thrownewIllegalStateException("Observer"+observer+"wasnotregistered.");
}
mObservers.remove(index);
}
}
publicvoidunregisterAll(){
synchronized(mObservers){
mObservers.clear();
}
}
}
总结:观察者模式看起来很高大上,其实说白了就是一个类维护了另一个类的一个集合,并通过这个集合绑定解绑或调用另一个类的方法,只不过,在设计底层框架时候,利用了多态的特性抽象出了接口和抽象类,以便适用于各种场合。其实在做终端页面时候完全用不到,因为多态只能增加运行时开销。然而,设置一个庞大系统时候,这种设计模式在面向对象的编程语言,可谓不能不用的手段了。
相关文章推荐
- [Android异常]listview(含上拉加载,上拉加载)下拉刷新报数组越界异常
- CircleProgressBar For Android(圆形进度条)
- android TouchEvent 处理流程
- Android 数据库升级完整解决方案
- (屏幕适配)鸿洋大神的Google百分比布局库 android-percent-support-extend
- Android - 文件读写操作 总结
- Android 双击返回键退出程序 实现
- Android+阿里大鱼+java/beans/Introspector,进来看看吧兄弟
- Android 使用代码为textview设置drawableLeft
- Android各种屏幕适配原理
- android——官方下拉刷新组件SwipeRefreshLayout(转)
- Android——使用Toolbar + DrawerLayout快速实现高大上菜单侧滑(转)
- 横竖屏切换导致国际化的问题
- android 闹钟设置的几种方法
- android中Tools属性
- 文章标题
- Android四大布局之帧布局及其运用
- Android SwipeRefreshLayout 官方下拉刷新控件使用
- Android之自定义view及自定义属性
- Android fragment 重叠问题——通过hide,show方式导致的解决方法