Android框架设计模式(三)——Observer Method
2016-03-23 21:03
579 查看
一观察者模式
什么是控制反转和依赖倒置
依赖倒置
控制反转
什么是观察者模式
定义
UML图
适用场景
二观察者模式在Android框架中的应用
BaseAdapter适配器
其他应用
抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。
总体来说,依赖倒置与控制反转都是一个意思:依赖于接口编程,将具体的对象之间的关系通过轻量型的接口来分离,框架层通过接口调用应用层的不同实现(此处即框架与应用层解耦),达到反向控制的目的。依赖倒置是原则,控制反转是体现。
一般来说,IOC有两种实现的方式:
(1)继承( Inheritance)+卡隼函数(hook)——在 Template Pattern中使用
(2)委托( Delegation)+卡隼函数(hook)——在Observer模式中使用
通俗举例:
通俗来说,举古代打仗为例,敌军为数据集合(被观察者),军官为视图(观察者)。那么中间的通知者就是侦察兵,侦察兵在前线侦查敌情的变动,一有风吹草动就会通知军官,然后军官采取相应的方案。这里军官就是观察者,侦察兵就是通知者(不同角度可能角色会转换)。
Android里面实现观察者模式是基于组合,而不是继承的。即,观察者和通知者都是镶嵌在ListView和Adapter中,这样的好处是降低了宿主ListView、Adapter与Observer和Observerable的耦合性。
Android里面ListView的观察者模式的开始是下面经典代码:
我们来看看setAdapter中做了什么事:
看了setAdapter源码,里面有两个地方是观察者模式使用的核心:
即:
ListView获取Adapter的通知者引用,然后通过Adapter.registerDataSetObserver(),让通知者Adapter获得ListView的观察者接口,这样就实现了双向沟通的通道,绑定完成。
我们再来看通知者BaseAdapter的源码
从上面的源码我们可以看到,BaseAdapter里面有一个Observerable通知者对象。在ListView调用了setAdapter()方法后,就实现了通知者与观察者的绑定,当Adapter里面的数据集合改变时,容器Activity通过调用Adapter.notifyDataSetChanged()然后再通过Observerable.notifyChanged方法通知ListView数据集改变了,然后就会调用ListView中DataObserver的onChaned()方法更新界面。
我们来看看真正的Observer和Observerable接口的源码。
ListView中的AdapterDataSetObserver源码:
Adapter中的DataSetObserverable源码:
由于Android框架系统比较复杂,因此它并没有采取Gof的实现接口的方式来实现观察者模式,而是通过委托的方式(嵌套一个通知者、观察者),委托通知者和观察者来实现通知和接收通知的任务。
比如:
广播机制中的BroadCast(通知者)和BroadReceiver(观察者);
Service中的Service(通知者)和ServiceConnection(观察者),当服务启动成功后,就调用onBind()方法通知ServiceConnection服务已经启动,通过 onServiceConnected()将Binder返回给观察者;
什么是控制反转和依赖倒置
依赖倒置
控制反转
什么是观察者模式
定义
UML图
适用场景
二观察者模式在Android框架中的应用
BaseAdapter适配器
其他应用
一、观察者模式
在介绍观察者模式之前,先补充两个概念:IOC(控制反转)、DIP(依赖倒置)。什么是控制反转和依赖倒置?
依赖倒置(控制反转),是框架设计的核心,因为有了它们会产生框架,框架的核心就是把【不变】的留在框架层次,把【变化】的留在应用层次,然后两个层次之间通过接口来实现沟通,降低耦合。它们两者本质是同样的,只是一个是从原则上面描述,一个是从方式上面描述。依赖倒置:
高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。
控制反转:
高层框架不应该依赖于底层的实现,底层的实现应该依赖于高层的框 架,高层框架封装不变的部分,把变化的部分留出接口让底层实现,通 过接口来实现高层与底层之间的沟通。在这个沟通的过程中,框架是主 动的(即调用者),而底层的具体应用实现是被动的(被调用者)。
总体来说,依赖倒置与控制反转都是一个意思:依赖于接口编程,将具体的对象之间的关系通过轻量型的接口来分离,框架层通过接口调用应用层的不同实现(此处即框架与应用层解耦),达到反向控制的目的。依赖倒置是原则,控制反转是体现。
一般来说,IOC有两种实现的方式:
(1)继承( Inheritance)+卡隼函数(hook)——在 Template Pattern中使用
(2)委托( Delegation)+卡隼函数(hook)——在Observer模式中使用
什么是观察者模式?
定义:
百度百科:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件(通知者)管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。通俗举例:
通俗来说,举古代打仗为例,敌军为数据集合(被观察者),军官为视图(观察者)。那么中间的通知者就是侦察兵,侦察兵在前线侦查敌情的变动,一有风吹草动就会通知军官,然后军官采取相应的方案。这里军官就是观察者,侦察兵就是通知者(不同角度可能角色会转换)。
UML图:
适用场景:
当一个对象的改变需要通知其它对象的时候,同时他又不知道具体有多 需要相互依赖的实体对象解耦,让他们共同依赖于抽象接口(类别), 这样即使两个具体对象有改动(只要接口没有变),也不会影响到对 方。而且观察者模式可以实现一个通知者,通知多个完全不同的观察 者。
二、观察者模式在Android框架中的应用
BaseAdapter适配器
Adapter(适配器),单独本身就是一种模式。但是在Android中,它还有另一个身份————观察者模式中的通知者。
Android里面实现观察者模式是基于组合,而不是继承的。即,观察者和通知者都是镶嵌在ListView和Adapter中,这样的好处是降低了宿主ListView、Adapter与Observer和Observerable的耦合性。
Android里面ListView的观察者模式的开始是下面经典代码:
MyAdapter adapter = new MyAdapter(); listView.setAdapter(adapter);
我们来看看setAdapter中做了什么事:
@Override public void setAdapter(ListAdapter adapter) { //解除之前的Observer if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } //清除之前的缓存,重新更新视图集合 resetList(); mRecycler.clear(); //获取通知者引用(Adapter) 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(); }
看了setAdapter源码,里面有两个地方是观察者模式使用的核心:
即:
//获取通知者引用(Adapter) if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mDataSetObserver = new AdapterDataSetObserver(); //调用通知者的方法注册观察者 mAdapter.registerDataSetObserver(mDataSetObserver);
ListView获取Adapter的通知者引用,然后通过Adapter.registerDataSetObserver(),让通知者Adapter获得ListView的观察者接口,这样就实现了双向沟通的通道,绑定完成。
我们再来看通知者BaseAdapter的源码
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { private final DataSetObservable mDataSetObservable = new DataSetObservable();//通知者引用 public boolean hasStableIds() { return false; } //注册观察者绑定 public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } //解除观察者绑定 public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * 通知已注册的观察者,数据集已经改变。任何观察者在收到该信息 * 之后必须更新自己。 */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } /** * Notifies the attached observers that the underlying data is no longer valid * or available. Once invoked this adapter is no longer valid and should * not report further data set changes. */ public void notifyDataSetInvalidated() { mDataSetObservable.notifyInvalidated(); } public boolean areAllItemsEnabled() { return true; } public boolean isEnabled(int position) { return true; } public View getDropDownView(int position, View convertView, ViewGroup parent) { return getView(position, convertView, parent); } public int getItemViewType(int position) { return 0; } public int getViewTypeCount() { return 1; } public boolean isEmpty() { return getCount() == 0; } }
从上面的源码我们可以看到,BaseAdapter里面有一个Observerable通知者对象。在ListView调用了setAdapter()方法后,就实现了通知者与观察者的绑定,当Adapter里面的数据集合改变时,容器Activity通过调用Adapter.notifyDataSetChanged()然后再通过Observerable.notifyChanged方法通知ListView数据集改变了,然后就会调用ListView中DataObserver的onChaned()方法更新界面。
我们来看看真正的Observer和Observerable接口的源码。
ListView中的AdapterDataSetObserver源码:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroll != null) { mFastScroll.onSectionsChanged(); } } @Override public void onInvalidated() { super.onInvalidated(); if (mFastScroll != null) { mFastScroll.onSectionsChanged(); } } }
Adapter中的DataSetObserverable源码:
public class DataSetObservable extends Observable<DataSetObserver> { /** * 通知观察者数据集改变了 */ public void notifyChanged() { synchronized(mObservers) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } public void notifyInvalidated() { synchronized (mObservers) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onInvalidated(); } } } }
由于Android框架系统比较复杂,因此它并没有采取Gof的实现接口的方式来实现观察者模式,而是通过委托的方式(嵌套一个通知者、观察者),委托通知者和观察者来实现通知和接收通知的任务。
其他应用
观察者模式在Android中的应用还有很多。比如:
广播机制中的BroadCast(通知者)和BroadReceiver(观察者);
Service中的Service(通知者)和ServiceConnection(观察者),当服务启动成功后,就调用onBind()方法通知ServiceConnection服务已经启动,通过 onServiceConnected()将Binder返回给观察者;
相关文章推荐
- [android] 隐式意图激活另外一个activity
- Android Studio SVN的使用
- Android中的5中数据存储方式之SharedPreferences存储
- Android手势源码浅析-----手势绘制(GestureOverlayView)
- Android Studio 设置内存大小及原理
- android 开发技巧(10,11)
- 常用的监听事件(android)
- Android Stability [转]
- [Android Studio] Android Studio常用快捷键
- android无效代码,资源文件,原生文件对apk大小的影响
- android 开发技巧(12)--更改 Toast 显示位置的技巧
- Android Studio实现侧滑菜单
- Android 通过ADB Wireless无线调试应用
- 【Android】通用系列 —— AbsListView适配器
- 【Android】4、分析HelloWorld项目如何运行
- Android中用户手势检测详述(OnCliskListener、OnTouchListener和GestureDetecter)
- Android相关的代码片段
- Android 高清加载巨图方案 拒绝压缩图片
- Android中的数据存储方式
- Android FragmentTransactionExtended:使Fragment以多种样式动画切换