观察者模式——Android适配器源码分析

观察者模式是开发中非常常见的一种设计模式,而且非常适合针对一对多的依赖时来使用。尤其是当某一个数据发生变化需要通知多个角色时。而在java中,一个标准的观察者模式有四个角色,分别是:抽象被观察者角色、抽象观察者模式、具体被观察者角色和具体观察者角色。

抽象被观察者角色
把所有观察者对象的引用封装到一个集合中,也就是说每个抽象主题角色可以有任意多个观察者。同时提供注册和取消注册的方法。

抽象观察者角色
为具体的观察者定义一个接口,在得到主题角色的通知时更新自己。

具体被观察者角色
在具体主题内部发生改变时,给所有等级过的观察者发送通知。

具体观察者角色
该角色实现抽象观察者角色所要求的更新接口,以便在具体主题角色发生改变时得到响应。

Android中适配器的抽象观察者和被观察者

抽象观察者

public abstract class DataSetObserver {
    /**
     * This method is called when the entire data set has changed,
     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
     */
    public void onChanged() {
        // Do nothing
    }

    /**
     * This method is called when the entire data becomes invalid,
     * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
     * {@link Cursor}.
     */
    public void onInvalidated() {
        // Do nothing
    }
}

抽象观察者类只提供了两个方法用来给实现类实现,分别是数据改变(onChanged方法)和数据无效(onInvalidated方法)。

抽象被观察者

public abstract class Observable<T> {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected final ArrayList<T> mObservers = new ArrayList<T>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must not already
     * be registered.
     */
    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);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    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);
        }
    }

    /**
     * Remove all registered observers.
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}

在抽象被观察者中,将观察者引用封装到集合中,通过提供注册观察者和取消观察者的方法来对集合数据进行维护。在维护观察者引用的集合时,通过同步锁来防止多个线程访问集合时对数据造成破坏。在抽象被观察者中,通过泛型让子类实现时保证观察者的引用的一致性。

Android适配器中的实现

在查看适配器中关于观察者的实现前,我们先看一下被观察者的实现,也就是具体被观察者。这个类完成了抽象观察者和抽象被观察者的依赖。

具体被观察者

public class DataSetObservable extends Observable<DataSetObserver> {
    /**
     * Invokes {@link DataSetObserver#onChanged} on each observer.
     * Called when the contents of the data set have changed.  The recipient
     * will obtain the new contents the next time it queries the data set.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }

    /**
     * Invokes {@link DataSetObserver#onInvalidated} on each observer.
     * Called when the data set is no longer valid and cannot be queried again,
     * such as when the data set has been closed.
     */
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }
}

从上面代码中,具体被观察者类中声明了两个方法,分别是通知观察者数据发生改变的方法(notifyChanged方法,适配器调用的notifySetChanged方法本质上就是调用的被观察者的这个方法)和通知观察者数据失效的方法(notifyInvalidated方法)。实际上就是通知在抽象被观察者中注册的每个观察者去执行各自的事件。

具体观察者

具体观察者在适配器中的声明是一个内部类,所在位置在AdapterView中。继承的是抽象观察者DaTaSetObserver,重写了onChanged和onInvalidate方法。

源码: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;
        }
    }

从具体被观察者和具体观察者所在的位置可以很清楚的理解,ListView是观察者,也就是需要继承自抽象观察者(DataSetObserver),去回调onChanged和onInvalidate方法,执行数据改变后的更新操作。

那么除了上面的具体被观察者和具体观察者,我们会发现还少了一个类,用来给被观察者去注册观察者。同时也是具体去调用数据改变的地方。

我们通过查找ListView的源码,发现在它的setAdapter方法中实现了上述操作:

源码: ListView#setAdapter

public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            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();
    }

重点看这几句:

mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);

从这里我们恍然大悟,ListView在设置适配器的时候就完成了注册观察者的操作。其中AdapterDataSetObserver就是AdapterView中的内部类,由于ListView是AdapterView的子类,所以ListView可以new父类(准确说是爷爷辈的)的内部类对象。拿到观察者后,就注册到被观察者中。

这里面是通过mAdapter调用的registerDataSetObserver方法。那么这个变量是哪里来的呢,通过查看源码,我们发现在ListView的父类AbsListView中有这个变量的声明:ListAdapter mAdapter;

在setAdapter方法中我们知道,ListAdapter是传递进来的参数类型。也就是说将观察者注册到被观察者中是在ListAdapter中声明的了?

然而并不是,而是在ListAdapter的父类(其实是接口)Adapter中声明的方法。最终在BaseAdapter中重写。(BaseAdapter是抽象类,实现了ListAdapter接口,而ListAdapter接口继承的Adapter接口。)也就是说mAdapter调用的实际上是BaseAdapter中的registerDataSetObserver方法。

源码: 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);
    }

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }
    ...
}

从源码中我们可以看到,在BaseAdapter中先new了DataSetObservable对象(具体被观察者)。然后在registerDataSetObserver方法中,调用DataSetObservable的registerObserver方法,将观察者注册到被观察者中。

总结一下:

  1. 首先是声明抽象的被观察者(Observable)用来维护观察者对象的集合和注册取消方法。

  2. 再声明一个抽象的观察者(DataSetObserver),声明了两个方法用来回调。

  3. 然后声明了一个具体被观察者(DataSetObservable),用来完成通知观察者的操作。

而在适配器的具体执行如下:

  1. 在ListView的setAdapter方法中,new了AdapterSetObserver(继承了具体观察者DataSetObserver,是AdapterView的内部类)对象,调用BaseAdapter的registerDataSetObserver方法,将观察者注册到被观察者中。

  2. 在BaseAdapter中先new了DataSetObservable对象(具体被观察者),然后在registerDataSetObserver方法中,执行了DataSetObservable的registerObserver方法。

  3. 在ListView的setAdapter方法中,BaseAdapter是通过实现ListAdapter接口,然后传递到方法中。

PS:实际上理清了思路,我们会发现观察者模式实际上很简单,只不过在Android的ListView和其对应的适配器中实现的观察者模式看起来比较复杂,但是只要弄通了整个流程,理解起来就很容易了。

鸣谢:http://blog.csdn.net/fangchongbory/article/details/7774044

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值