在BaseAdapter源码中了解观察者模式

来源:互联网 发布:周扬青淘宝店铺货源 编辑:程序博客网 时间:2024/05/17 23:32

转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/76146635
本文出自:【顾林海的博客】

前言

观察者模式也叫发布订阅模式,它是定义如下:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。适用的适用场景主要有关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系;事件多级触发场景;跨系统的消息交互场景,如消息队列、事件总线的处理机制。比如现在非常主流的EventBus, RxJava等框架就是采用的观察者模式。

类图说明



观察者模式的通用类图如下:

这里写图片描述

Subject被观察者,定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。
Observer观察者,观察者接受到消息后,即更新操作,对接收到的信息进行处理。
ConcreteSubject具体的被观察者,定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
ConcreteObserver具体的观察者,每个观察在接收到消息后的处理反应是不同,各个观察者自己的处理逻辑。


日常案例



在日常中比如订阅新闻邮件就是一种典型的观察者模式,用户邮箱是观察者,新闻网站是被观察者,一旦新闻网站有新闻更新,会通知用户并给用户邮箱发送新闻。


创建新闻的实体类NewsBean:

/** * 新闻实体类 */public class NewsBean {    public String title;    public String info;}



创建观察者(Email)接口:

public interface EmailObserver<T> {    void update(T news);}



创建观察者(Email)具体实现类:

public class Email implements EmailObserver<NewsBean> {    private String user;    public Email(String user) {        this.user = user;    }    @Override    public void update(NewsBean news) {        System.out.println("尊敬的" + user + "用户,收到一封新闻邮件,标题为:" + news.title);    }}



创建被观察者(新闻网站)抽象类:

public abstract class NewObservable<T> {    private List<EmailObserver> observers = new ArrayList<>();    public void registerObserver(EmailObserver observer) {        if (!observers.contains(observer)) {            observers.add(observer);        }    }    public void unregisterObserver(EmailObserver observer) {        if (observers.contains(observer)) {            observers.remove(observer);        }    }    public void notifyObserver(T t) {        for (EmailObserver emailObserver : observers) {            emailObserver.update(t);        }    }    public void clearAllObserver() {        observers.clear();    }}



NewObservable类中提供了观察者的添加、取消以及通知操作的实现。


创建被观察者(新闻网站)的具体实现:

public class NewService extends NewObservable<NewsBean> {    public void make() {        NewsBean newsBean = new NewsBean();        newsBean.title = "号外,号位,某某程序员居然找到女朋友了";        newsBean.info = "新闻内容.....";        notifyObserver(newsBean);    }



最后在场景类中使用:

public class Client {    public static final void main(String[] args) {        //创建被观察者新闻网站        NewService newService = new NewService();        //创建一些观察者用户        Email user1 = new Email("用户1");        Email user2 = new Email("用户2");        Email user3 = new Email("用户3");        //将观察者添加到被观察中        newService.registerObserver(user1);        newService.registerObserver(user2);        newService.registerObserver(user3);        //被观察者(网站)发布一则新闻        newService.make();    }}


运行结果:
尊敬的用户1用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了
尊敬的用户2用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了
尊敬的用户3用户,收到一封新闻邮件,标题为:号外,号位,某某程序员居然找到女朋友了

Android源码中观察者模式的使用



在平时开发中,ListView用的比较多,可以通过setAdapter(adapter)方法给ListView设置适配器,其中的BaseAdapter就是实现了观察者模式。


被观察者(BaseAdapter)



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);    }    /**     * 通知观察者(ListView重绘当前可见区域)     */    public void notifyDataSetChanged() {        mDataSetObservable.notifyChanged();    }    /**     * 通知观察者(ListView会重绘控件)     */    public void notifyDataSetInvalidated() {        mDataSetObservable.notifyInvalidated();    }}



查看BaseAdapter会发现它就是一个观察者模式,其中的DataSetObservable是一个数据集的观察者,并且在BaseAdapter源码中实现了被观察者职责方法:动态地增加、取消观察者,管理观察者并通知观察者。其中notifyDataSetChanged()方法是用于通知ListView重绘当前的可见区域,notifyDataSetInvalidated()方法用于通知ListView重绘控件。



DataSetObservable承载这被观察者的职责,查看DataSetObservable源码:

public class DataSetObservable extends Observable<DataSetObserver> {    /**     * 同步操作,通知观察者(这里是ListView)     */    public void notifyChanged() {        synchronized(mObservers) {            /**             * 遍历观察者,并通知             */            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onChanged();            }        }    }    /**     * 同步操作,通知观察者(这里是ListView)     */    public void notifyInvalidated() {        synchronized (mObservers) {            /**             * 遍历观察者,并通知             */            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onInvalidated();            }        }    }}


DataSetObservable内部实现了通知观察者(ListView)的方法,并继承自Observable泛型类,我们继续看Observable的源码,其实到这里大家应该能知道Observable类具体做了哪些操作,一定提供了对观察者的注册和取消注册操作,这里继承Observable泛型类时指定了具体的观察者类型是DataSetObserver,这里先提下DataSetObserver 这个观察者是在ListView某个父类中定义,其实也就很好的说明了ListView是观察者,观察实现了BaseAdapter类中的数据变化,一旦数据产生变化,通过BaseAdapter的notifyChanged()方法通知ListView的重绘。



Observable源码:

public abstract class Observable<T> {    /**     * 用于保存观察者的列表     */    protected final ArrayList<T> mObservers = new ArrayList<T>();    /**     * 添加注册一个观察者到观察者列表中。     */    public void registerObserver(T observer) {        if (observer == null) {            throw new IllegalArgumentException("The observer is null.");        }        synchronized(mObservers) {            if (mObservers.contains(observer)) {                throw new IllegalStateException("Observer " + observer + " is already registered.");            }            mObservers.add(observer);        }    }    /**     * 从列表中移除(取消注册)观察者。     */    public void unregisterObserver(T observer) {        if (observer == null) {            throw new IllegalArgumentException("The observer is null.");        }        synchronized(mObservers) {            int index = mObservers.indexOf(observer);            if (index == -1) {                throw new IllegalStateException("Observer " + observer + " was not registered.");            }            mObservers.remove(index);        }    }    /**     * 情况所有观察者     */    public void unregisterAll() {        synchronized(mObservers) {            mObservers.clear();        }    }}


Observable内部提供了一个用于保存观察者的列表,并提供了registerObserver(observer)方法用于注册观察到列表中,unregisterObserver(observer)方法用于从观察者列表移除一个观察者,以及unregisterAll()方法清空所有观察者。



到这里整个被观察者(BaseAdatper)已经分析完毕,这里总结一些知识点:

  1. BaseAdapter内部绑定了一个被观察者的数据集的类(DataSetObservable)。
  2. DataSetObservable内部实现了两个通知观察者的方法,分别是notifyChanged()和notifyInvalidated()方法。
  3. DataSetObservable继承自Observable泛型类,具体观察者对象是DataSetObserver(ListView内部实现类)。
  4. DataSetObservable(被观察者)提供了观察者的注册(存放在列表中)方法、取消注册(从列表中移除)以及清空所有观察者。

观察者(ListView)



在给ListView添加适配器时,会调用ListView的setAdapter(adapter)方法,接下来从ListView的setAdater(adapter)方法的具体实现进行深入:

@Overridepublic void setAdapter(ListAdapter adapter) {    /**     * (1)第一次为ListView设置适配器时,如果已经存在观察者,就将它移除。     */    if (mAdapter != null && mDataSetObserver != null) {        mAdapter.unregisterDataSetObserver(mDataSetObserver);    }    resetList();    mRecycler.clear();    if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {        mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);    } else {        mAdapter = adapter;    }    mOldSelectedPosition = INVALID_POSITION;    mOldSelectedRowId = INVALID_ROW_ID;    super.setAdapter(adapter);    if (mAdapter != null) {        mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();        mOldItemCount = mItemCount;        mItemCount = mAdapter.getCount();        checkFocus();        /**         * (2)创建观察者。         */        mDataSetObserver = new AdapterDataSetObserver();        /**         * (3)将观察者注册到被观察者中。         */        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一开始就会去判断观察者是否存在,如果已经存在就会取消注册,在(2)中,会创建观察者,并在(3)中添加到被观察者中,AdapterDataSetObserver定义在ListView父类中。



AbsListView内部类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();        }    }}



回到BaseAdapter中,在调用BaseAdapter的notifyChanged方法时会执行继承自Observable 泛型类的DataSetObservable中的notifyChanged()方法,在这个方法中去遍历父类中的观察者列表,并调用它们的onChanged()和onInvalidated()方法,在上面分析被观察者(BaseAdapter)时,已经知道了观察者的实例类是DataSetObserver,而AbsListView内部类AdapterDataSetObserver继承自 AdapterView内部类AdapterDataSetObserver。



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();    }    @Override    public void onInvalidated() {        mDataChanged = true;        if (AdapterView.this.getAdapter().hasStableIds()) {            // Remember the current state for the case where our hosting activity is being            // stopped and later restarted            mInstanceState = AdapterView.this.onSaveInstanceState();        }        // Data is invalid so we should reset our state        mOldItemCount = mItemCount;        mItemCount = 0;        mSelectedPosition = INVALID_POSITION;        mSelectedRowId = INVALID_ROW_ID;        mNextSelectedPosition = INVALID_POSITION;        mNextSelectedRowId = INVALID_ROW_ID;        mNeedSync = false;        checkFocus();        requestLayout();    }    public void clearSavedState() {        mInstanceState = null;    }}



由于AbsListView内部类AdapterDataSetObserver重写了 AdapterView内部类AdapterDataSetObserver的onChanged()和onInvalidated()方法 。也就是说BaseAdapter的notifyChanged最终执行到ListView的父类AbsListView的内部类AdapterDataSetObserver中的onChanged()和onInvalidated()方法,查看这两个方法可以看出它们调用了父类的onChanged()和onInvalidated()方法,可以看出ListView重绘的具体实现是在AdapterView内部类AdapterDataSetObserver类中实现的,在onChanged()和onInvalidated()方法中最终调用requestLayout()方法进行ListView、GridView等AdapterView组件的重新布局。


到这里整个观察者(ListView)已经分析完毕,这里总结一些知识点:

  1. 通过给setAdapter(adapter)方法进行观察者的注册。
  2. 被观察者通过notifyChanged()方法通知观察者(AbsListView内部类 AdapterDataSetObserver中的 onChanged()和onInvalidated()方法 )进行处理。
  3. AdapterDataSetObserver继承自AdapterView内部类AdapterDataSetObserver,并交由它来进行AdapterView组件的重新布局。
原创粉丝点击