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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/GULINHAI12/article/details/76146635

转载请标明出处:
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)方法的具体实现进行深入:
@Override
public 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组件的重新布局。

猜你喜欢

转载自blog.csdn.net/GULINHAI12/article/details/76146635