观察者模式

           在android的开发过程中,观察者模式是一个使用非常频繁的模式,而且在很多的源码当中也可以找到他们的身影,这个模式的一个重要作用就是解耦,将被观察者和观察者进行解耦,使得它们之间的依赖性更小,也有利于代码的维护和扩展。

 

定义

    定义对象间一种一对多的依赖关系,使得每当一个对象状态发生改变,则所有依赖于它的对象都会得到通知并被自动更新

 

使用场景

     1》关联行为场景,需要注意的是,关联行为是可拆分的,而不是"组合"关系

     2》事件多级触发场景

     3》跨系统的消息交换场景,如消息队列,事件总线的处理机制

 

Java中的观察者模式

/**
 * 观察者
 */
public class RealObserver implements Observer {

    public String mName;

    public RealObserver(String name) {
        this.mName = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(mName+"更新内容了,快来看看吧");
    }
}
/**
 * 被观察者
 */
public class RealObservable extends Observable {

    public void addNewContent(String content) {
        setChanged();
        notifyObservers(content);
    }
}
public class Test {

    public static void main(String[] args) {
        // 被观察者
        RealObservable realObservable = new RealObservable();
        // 观察者
        RealObserver realObserver = new RealObserver("泡沫之夏");
        RealObserver realObserver1 = new RealObserver("会有天使替我爱你");
        RealObserver realObserver2 = new RealObserver("黎明前的黑暗");
        // 将观察者注册到可观察对象的观察者列表中
        realObservable.addObserver(realObserver);
        realObservable.addObserver(realObserver1);
        realObservable.addObserver(realObserver2);
        // 发布消息
        realObservable.addNewContent("有新内容进行更新了");
    }
}

最后的输出结果是:

那么现在我们先来看看Java中的观察者模式的源码,看看它里面到底是怎么执行的

首先我们来看观察者Observer

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);
}

非常简单,只是一个接口,里面有一个update方法,但是请稍微留意一下这两个参数,第一个参数代表的是具体的哪个观察者对象,第二个参数代表的是更新的内容

 

接下来我们来看看被观察者,即Observable

public class Observable {
    // 是否需要发生更新通知
    private boolean changed = false;
	// 集合:继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能
	// 用来保存所有的观察者
    private Vector<Observer> obs;


    public Observable() {
        obs = new Vector<>();
    }

  
    // 添加观察者
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

  
    // 移除观察者
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

	
	// 给所有的观察者发送通知(发送的内容信息为空)
    public void notifyObservers() {
        notifyObservers(null);
    }

  
    // 遍历所有的观察者,并发送通知
    public void notifyObservers(Object arg) {
       
        Object[] arrLocal;

        synchronized (this) {      
            if (!hasChanged())
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    // 删除所有的观察者
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    // 设置通知状态
    protected synchronized void setChanged() {
        changed = true;
    }

    // 清除通知状态
    protected synchronized void clearChanged() {
        changed = false;
    }

    // 获取通知状态
    public synchronized boolean hasChanged() {
        return changed;
    }

    // 获取观察者对象的数量
    public synchronized int countObservers() {
        return obs.size();
    }
}

被观察者的源码也非常简单,就是使用一个集合来保存观察者对象,然后提供了对观察者对象的增删的方法,最后提供了一个方法用来循环遍历所有的观察者对象并触发update()方法

 

Android中的观察者模式

            在android开发过程中,ListView是一个非常好用的控件,尽管它现在已经被RecyclerView所代替,但是这并不影响我们对于它的源码的分析。今天,我们就通过分析ListView来加深对观察者模式的理解。我们知道,在更新数据的时候我们只需要一行代码notifyDataSetChanged()方法就可以搞定,那么我们先来看看这行代码做了什么

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    // 数据集观察者
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    private CharSequence[] mAutofillOptions;

    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();
    }

    // 省略代码
}

可以看到,对于ListView而言,在其内部也是通过观察者模式来通知界面进行更新的,当我们调用notifyDataSetChanged()方法的时候,会调用被观察者的notifyChanged()方法,那么我们来看看notifyChanded()方法做了什么

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();
            }
        }
    }
}

可以看到,notifyChanged()方法也很简单,就是对所有的观察者对象进行遍历执行onChanged()方法

 

那么现在就有一个疑问了,我们的观察者是从哪里来的呢?这个时候我们就需要看看当我们setAdapter()的时候里面做了啥

@Override
public void setAdapter(ListAdapter adapter) {
        // 如果已经有了一个adapter,那么先注销该adapter对应的观察者 
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        // 代码省略
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            // 获取数据的数量
	    mItemCount = mAdapter.getCount();
            checkFocus();
            // 注册一个数据集观察者
            mDataSetObserver = new AdapterDataSetObserver();
            // 将观察者注册到adapter中
	    mAdapter.registerDataSetObserver(mDataSetObserver);
            // 代码省略
        } else {
            // 代码省略
        }
        // 更新界面
        requestLayout();
}

从上面可以看出,在设置Adapter时会构建一个AdapterDataSetObserver,也就是观察者,最后,将这个观察者注册到Adapter中,这样我们的被观察者,观察者都有了。那么,AdapterDataSetObserver又是什么呢?我们来看看

 

AdapterDataSetObserver是在AbsListView里面

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();
            }
        }
    }

而它又继承自AbsListView的父类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();
        }

到这里我们就知道了,总结一下:

1.AdapterView里面有一个内部类AdapterDataSetObserver,在ListView设置adapter的时候会构建一个AdapterDataSetObserver并且注册到Adapter中

2.在Adapter中包含一个数据集可观察者DataSetObservable,在数据数量发生改变时,开发者手动调用Adapter.notifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable函数,该函数会遍历所有观察者的onChanged()函数

3.在AdapterDataSetObserver的onChanged函数中获取Adapter中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,更新用户界面

到这里,我们的观察者模式就分析完毕了,欢迎大家在下面留言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值