Android 观察者模式

观察者模式,是一种非常常见的设计模式,在很多系统中随处可见,尤其是涉及到数据状态发生变化需要通知的情况下。
本文以AbstractCursor为例子,展开分析。
观察者模式,Observer Pattern,是一个很实用的模式,本人曾经接触到的各种平台以及曾经参与项目中打印模板解释器中都用到了此模式。

1.意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
热门词汇:依赖 发布-订阅 事件 通知 更新 监听 



观察者模式:观察者和被观察者


1.观察者接收到消息后,即进行update更新操作,对接收到的信息进行处理。

   一个类如果实现观察者的接口,则只需要实现一个update()方法,注意还需要在此类中添加一个被观察者(主题(被观察者)的实例.addObserver(this);)this指实现了观察者接口的对象

观察者模式有什么优点呢
观察者和被观察者之间是抽象耦合的,不管是增加观察者还是被观察者都非常容易扩展。
根据单一职责原则,每个类的职责是单一的,那么怎么把各个单一的职责串联成真实的复杂的逻辑关系呢,观察者模式可以起到桥梁作用。
观察者模式是松耦合的典型。 简单的代码如下:

  public class ObserverObj extends Activity implements Observer{

     private ObservableObj observableObjChange; 

       @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_service);
cx = this;

                // 在哪个类中使用观察者时必须把实现了该接口的观察者(订阅者)添加到被观察者(发布者)中,方便发布者发布信息时通过notify方法时能被观察者接收到变化的数据。

ObservableObj .getObservableObj ().addObserver(this);

         }


     @Override
public void update(Observable observable, Object data) {
observableObjChange = (ObservableObj ) observable;
List<Tree> list = observableObjChange.getList();
Message message = Message.obtain();
message.what = 1;
message.obj = list;

               // 交由主线程去更新ui控件
handler.sendMessage(message);

}


 }



2. 被观察者(发布者)是一个接口或者是抽象类,定义被观察者必须实现的职责,它必须能偶动态地增加、取消观察者(订阅者),管理观察者并通知观察者(android自带的被观察者已经封装好添加、取消、移除观察者对象)。

   一个类实现被观察者的接口,

  public class ObservableObj extends Observable {

          public static ObservableObj observableObj;

          public static ObservableObj getObservableObj () {
   if (observableObj== null) {
  observableObj= new ObservableObj ();
   }
   return observableObj;
   }


        //被观察者中数据源发生变化后执行以下代码

setChanged();
//之后去执行ObserverObj 中重写的update()
notifyObservers();
       


 }


注:使用android自带的观察者模式的话,实现被观察者接口的类中当数据源发生变化时候,只需要执行通知观察者就可以

       setChanged();
//之后去执行ObserverObj 中重写的update()
notifyObservers();

        之后观察者那边执行update()方法

如果不适用Android自带的观察者的话,只需要在声明的被观察者的接口中声明添加、取消、移除、通知(notifyObservers)观察者对象的方法

                                                                      在声明的观察者的接口中声明更新的方法即可


在Android源码中,其中一个经典的使用到观察者模式的就是Android控件的事件监听模型。 
一、下面简要说明Android交互事件传输的设计原理和特征: 
交互事件,是指当用户通过按键、触摸、滑动等操作与应用进行交互时触发的相关事件。通过Android控件树可知,交互事件是沿着控件树自顶向下传播的。其中Android控件树简要图如下所示: 


 
当位于控件树上层的父控件收到交互事件后,会先行判定该事件的目标控件对象,如果该事件正是自己所需要的,则会截获事件进行处理,否则就尝试将事件向下分发给对应的子控件,并对推的逐级向下传播事件,直至该事件被处理或者忽略。 

Android在View类中定义了一系列命名为View.On***的事件函数用来接收和处理各类交互事件,如通过View.OnKeyDown函数可以接收到用户的按键操作等。每个派生自View类的子控件都可以通过重载这些事件函数,来处理该控件所需的事件。 

例如,如果一个控件需要处理用户按返回键的操作,则可以通过重载View.onKeyDown函数来实现: 
复制代码代码如下:

/* 
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent) 
*/ 
@Override 
public boolean onKeyDown(int keyCode, KeyEvent event) { 
// 监听和处理返回操作 
if(keyCode == KeyEvent.KEYCODE_BACK) { 
doSomething(); 
return true; 

return false; 


事件函数的返回值是控制事件传播的重要手段。如果事件函数返回true,则说明该控件已经接收并完成了该事件的处理,无须将该事件进一步传递;反之,如果事件函数返回false,则说明该控件对象未能处理该事件(或虽然做过处理,但仍需要进一步处理),需要继续传递以寻找能够处理它的控件对象。 

对于容器控件ViewGroup来说,它的一个职责就是将交互事件传播到其子控件中。针对不同的事件,ViewGroup可以选择不同的传播方式。如,如果是触摸事件,ViewGroup对象需要判定该事件发生的区域位于哪个子控件上,从而将该事件分配给该子控件进行处理。但通过继承的方式来进行事件处理并不够灵活,会导致系统中出现大量的子控件类型,并且各个控件的复用性都较差。因此采用“组合”来代替“继承”。基于此思想,View类中提供了一系列配套的事件监听函数供开发者处理对应事件,这就有了使用观察者模式来完成Android控件的事件监听模型。开发者可以构造外部观察者对象与控件对象的事件监听接口绑定,获取事件消息。 
还是以上面的按键事件为例,通过监听者进行处理的实现如下所示 : 
复制代码代码如下:

final View.OnKeyListener listener = new OnKeyListener() { 
@Override 
public boolean onKey(View v, int keyCode, KeyEvent event) { 
// 处理返回键事件 
if(keyCode == KeyEvent.KEYCODE_BACK) { 
doSomething(); 
return true; 

return false; 

}; 
。。。 
mUISetButton = (Button) findViewById(R.id.setValue); 
// 将按钮与监听对象绑定 
mUISetButton.setOnKeyListener(listener); 

通过利用外部对象来处理交互事件,其耦合性低,使每个类控件都具有更好的可复用度,无须为了处理事件而构造新的控件。 
二、现在开始看看源代码是怎么进行组织使用“观察者模式”的  
1. 看View类源代码中的OnKeyListener接口: 
复制代码代码如下:

/** 
* Interface definition for a callback to be invoked when a key event is 
* dispatched to this view. The callback will be invoked before the key 
* event is given to the view. 
*/ 
public interface OnKeyListener { 
/** 
* Called when a key is dispatched to a view. This allows listeners to 
* get a chance to respond before the target view. 

* @param v The view the key has been dispatched to. 
* @param keyCode The code for the physical key that was pressed 
* @param event The KeyEvent object containing full information about 
* the event. 
* @return True if the listener has consumed the event, false otherwise. 
*/ 
boolean onKey(View v, int keyCode, KeyEvent event); 


2. 再看View类定义了私有成员mOnKeyListener(通过组合的方式): 
private OnKeyListener mOnKeyListener; 
3. 注册listener 
复制代码代码如下:

/** 
* Register a callback to be invoked when a key is pressed in this view. 
* @param l the key listener to attach to this view 
*/ 
public void setOnKeyListener(OnKeyListener l) { 
mOnKeyListener = l; 


4. 剩下的就交给开发者自己构造外部观察者对象与该按键的事件接口进行绑定,获取事件消息。 
最后让我们记住支撑“观察者模式”的设计原则: Strive for loosely coupled designs between objects that interact. 


详情可参考:http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Daniel-yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值