`
king_tt
  • 浏览: 2083464 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Android中的观察者模式的应用----ListView的源码解析

 
阅读更多
讲解ListView之前,我在这里首先讲解一下观察者模式。

java中的观察者模式,可以使用jdk提供的两个类进行快速实现。这两个类分别是java.util.Observable和java.util.Observer。
在讲解这两个类之前,先讲解一下观察者模式原理的东西:

从图上可以看出,当被观察者状态发生变化时,需要通知所有的观察者。要想实现这样的效果,那么被观察者里面必须持有观察者对象的引用
列表。设计的时候一定要注意解耦和通用性。
看下java.util.Observable和java.util.Observer这两个类的源码。

先看下观察者:

/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author  Chris Warth
* @version %I%, %G%
* @see     java.util.Observable
* @since   JDK1.0
*/  
public interface Observer {  
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */  
    void update(Observable o, Object arg);  
}  
Observer这个类,仅仅是定义的一个接口,这个接口可以达到解耦和通用性的效果,当观察者需要被通知的时候,调用下updata()这个方法即可。
再看下被观察者
[java] view plaincopy

public class Observable {  
    private boolean changed = false;  
    private Vector obs;  
     
    /** Construct an Observable with zero Observers. */  
  
    public Observable() {  
    obs = new Vector();  
    }  
  
    /**
     * Adds an observer to the set of observers for this object, provided  
     * that it is not the same as some observer already in the set.  
     * The order in which notifications will be delivered to multiple  
     * observers is not specified. See the class comment.
     *
     * @param   o   an observer to be added.
     * @throws NullPointerException   if the parameter o is null.
     */  
    public synchronized void addObserver(Observer o) {  
        if (o == null)  
            throw new NullPointerException();  
    if (!obs.contains(o)) {  
        obs.addElement(o);  
    }  
    }  
  
    /**
     * Deletes an observer from the set of observers of this object.  
     * Passing <CODE>null</CODE> to this method will have no effect.
     * @param   o   the observer to be deleted.
     */  
    public synchronized void deleteObserver(Observer o) {  
        obs.removeElement(o);  
    }  
  
    /**
     * If this object has changed, as indicated by the  
     * <code>hasChanged</code> method, then notify all of its observers  
     * and then call the <code>clearChanged</code> method to  
     * indicate that this object has no longer changed.  
     * <p>
     * Each observer has its <code>update</code> method called with two
     * arguments: this observable object and <code>null</code>. In other  
     * words, this method is equivalent to:
     * <blockquote><tt>
     * notifyObservers(null)</tt></blockquote>
     *
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#hasChanged()
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     */  
    public void notifyObservers() {  
    notifyObservers(null);  
    }  
  
    /**
     * If this object has changed, as indicated by the  
     * <code>hasChanged</code> method, then notify all of its observers  
     * and then call the <code>clearChanged</code> method to indicate  
     * that this object has no longer changed.  
     * <p>
     * Each observer has its <code>update</code> method called with two
     * arguments: this observable object and the <code>arg</code> argument.
     *
     * @param   arg   any object.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#hasChanged()
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     */  
    public void notifyObservers(Object arg) {  
    /*
         * a temporary array buffer, used as a snapshot of the state of
         * current Observers.
         */  
        Object[] arrLocal;  
  
    synchronized (this) {  
        /* We don't want the Observer doing callbacks into
         * arbitrary code while holding its own Monitor.
         * The code where we extract each Observable from  
         * the Vector and store the state of the Observer
         * needs synchronization, but notifying observers
         * does not (should not).  The worst result of any  
         * potential race-condition here is that:
         * 1) a newly-added Observer will miss a
         *   notification in progress
         * 2) a recently unregistered Observer will be
         *   wrongly notified when it doesn't care
         */  
        if (!changed)  
                return;  
            arrLocal = obs.toArray();  
            clearChanged();  
        }  
  
        for (int i = arrLocal.length-1; i>=0; i--)  
            ((Observer)arrLocal).update(this, arg);  
    }  
  
    /**
     * Clears the observer list so that this object no longer has any observers.
     */  
    public synchronized void deleteObservers() {  
    obs.removeAllElements();  
    }  
  
    /**
     * Marks this <tt>Observable</tt> object as having been changed; the  
     * <tt>hasChanged</tt> method will now return <tt>true</tt>.
     */  
    protected synchronized void setChanged() {  
    changed = true;  
    }  
  
    /**
     * Indicates that this object has no longer changed, or that it has  
     * already notified all of its observers of its most recent change,  
     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.  
     * This method is called automatically by the  
     * <code>notifyObservers</code> methods.  
     *
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     */  
    protected synchronized void clearChanged() {  
    changed = false;  
    }  
  
    /**
     * Tests if this object has changed.  
     *
     * @return  <code>true</code> if and only if the <code>setChanged</code>  
     *          method has been called more recently than the  
     *          <code>clearChanged</code> method on this object;  
     *          <code>false</code> otherwise.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#setChanged()
     */  
    public synchronized boolean hasChanged() {  
    return changed;  
    }  
  
    /**
     * Returns the number of observers of this <tt>Observable</tt> object.
     *
     * @return  the number of observers of this object.
     */  
    public synchronized int countObservers() {  
    return obs.size();  
    }  
}  

被观察者是抽象类,实现类继承就可以了。被观察者必须完成两件事,第一是注册观察者,第二就是通知观察者。
先看下一步:注册观察者

通过这个方法进行注册观察者:

    public synchronized void addObserver(Observer o) {  
        if (o == null)  
            throw new NullPointerException();  
    if (!obs.contains(o)) {  
        obs.addElement(o);  
    }  
    }  

obs是一个集合,用来存放观察者的:
  • private Vector obs;

第二部:通知观察者

通过这个方法通知的观察者:

 public void notifyObservers(Object arg) {  
    /*
         * a temporary array buffer, used as a snapshot of the state of
         * current Observers.
         */  
        Object[] arrLocal;  
  
    synchronized (this) {  
        /* We don't want the Observer doing callbacks into
         * arbitrary code while holding its own Monitor.
         * The code where we extract each Observable from  
         * the Vector and store the state of the Observer
         * needs synchronization, but notifying observers
         * does not (should not).  The worst result of any  
         * potential race-condition here is that:
         * 1) a newly-added Observer will miss a
         *   notification in progress
         * 2) a recently unregistered Observer will be
         *   wrongly notified when it doesn't care
         */  
        if (!changed)  
                return;  
            arrLocal = obs.toArray();  
            clearChanged();  
        }  
  
        for (int i = arrLocal.length-1; i>=0; i--)  
            ((Observer)arrLocal).update(this, arg);  
    }  



这个方法是同步的。
从21行代码可以看出:如果能通知到观察者,必须是changed=true才行,
所以调用这个方法之前要调用一下这个方法:
  • protected synchronized void setChanged() {
  • changed = true;
  • }

通知完成之后,在把changed设置为false:
  • protected synchronized void clearChanged() {
  • changed = false;
  • }


这里就是java中的观察者模式的实现,下面请看一个实现的例子

import java.util.Observable;  
import java.util.Observer;  
  
public class TestObservable {  
  
    public static void main(String[] args) {  
        // 创建一个被监听者  
        MyObservable observable = new MyObservable();  
        //创建三个监听者  
        MyObserver observer1 = new MyObserver();  
        MyObserver observer2 = new MyObserver();  
        MyObserver observer3 = new MyObserver();  
        //注册监听者  
        observable.addObserver(observer1);  
        observable.addObserver(observer2);  
        observable.addObserver(observer3);  
        //如果数据发生变化就通知观察者  
        observable.updateData(2);  
         
    }  
  
}  
/**
* Observable代表被观察者,如果被观察者有变化的话,要通知观察者
* @author suchangli
*
*/  
class MyObservable extends Observable{  
      
    private int oldarg = 0;  
      
    //这个方法就是用来注册监听者的  
    @Override  
    public synchronized void addObserver(Observer o) {  
        super.addObserver(o);  
    }  
    //用于删除指定的观察者  
    @Override  
    public synchronized void deleteObserver(Observer o) {  
        // TODO Auto-generated method stub  
        super.deleteObserver(o);  
    }  
    //下面两个重载方法是用来通知监听者的  
    @Override  
    public void notifyObservers() {  
        super.notifyObservers();  
    }  
    @Override  
    public void notifyObservers(Object arg) {  
        super.notifyObservers(arg);  
    }  
      
    public void updateData(int arg){  
        //通知监听者之前必须调用setChanged方法,否则通知不到监听者  
        if(arg>=0&&arg != oldarg){  
              
            this.setChanged();  
              
            this.notifyObservers(arg);  
              
            //最后把改变的标记清除掉  
            this.clearChanged();  
        }  
         
         
    }  
      
}   
/**
* Observer代表观察者,当被观察者有变化时,将会被通知到
* Observer仅仅实现update方法即可,会在这个方法里接到通知
* @author suchangli
*
*/  
class MyObserver implements Observer{  
    //第一个参数是被观察者对象,arg是传过来的参数,可能为null  
    @Override  
    public void update(Observable o, Object arg) {  
        System.out.println(this+":"+arg);  
    }  
      
}



对观察者模式做一下总结:
很多设计模式都可以用高焕堂老师的EIT造型,通过组合变形的方式去实现,用这一个造型可以是很多设计模式通俗易懂。
有兴趣的可以自己去网上搜搜EIT到底是什么东西。

1.Observer模式的优点:
(1)被观察者只需要知道谁在观察它,无需知道具体的观察细节
(2)被观察者一旦发生变化,只需要通过广播的方式告知观察者,至于消息如何到达则不需知道。这样的话无疑消除了被观察者和观察者之间通信的硬编码
(3)当一个被观察者同时被多个观察着观察时,观察者可以只选择自己感兴趣的事件,而忽略其它的事件

(4)多个观察者组合起来可以形成一个观察链,如果一旦需要回滚多个操作,此时观察链可以发挥作用
(5)观察者可以实时对被观察对象的变化做出响应,例如自动告警、中断运行等

2.运用Observer模式可以
(1)屏蔽线程间的通信机制:例如两个线程之间,主线程可以作为观察者,执行线程是被观察者。彼此之间只知道对方存在,但不知道之间通信的细节
(2)消除硬编码:如果没有Observer模式,则只能采用回调的模式,或者在代码中显示地调用观察者
(3)优化异常机制:特别适合在异常发生时向顶层监控,减少try-catch代码量

观察者模式有下面的一些缺点:
(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics