Android设计模式 — 观察者模式

来源:互联网 发布:孕囊数据看男女已验证 编辑:程序博客网 时间:2024/05/29 03:36

我们考虑一个实际中比较常见的情况:我们进行数据显示的时候经常会用到ListView,并且会使用到分页加载机制,用于降低网络数据传输的延迟。那么当ListView中的数据改变的时候(比如加载下一页),我们会使用adapter.notifyDataSetChanged()来通知改变数据的显示,那么,这种机制是什么呢?显然,这是使用了“观察者模式”的设计思维。那么,对于GridView 甚至ViewPager是否也适用呢?我们以ListView来分析,慢慢分析...

我们来回顾一下我们使用ListView显示列表的步骤:

listView = (ListView) findViewById(R.id.listView);  adapter = new MyAdapter();//MyAdapter为自定义的Adapter,继承自BaseAdapterlistView.setAdapter(adapter);//给ListView设置自定义的适配器

那么,第三行代码到底做了什么呢?我们来看看源码:(ListView.java)

public void setAdapter(ListAdapter adapter) {        if (mAdapter != null && mDataSetObserver != null) {            mAdapter.unregisterDataSetObserver(mDataSetObserver);        }        resetList();        mRecycler.clear();        //作者注:是否需要添加HeadView 和 FootView        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();    }
可以看出来,其实setAdapter(adapter)做的是注册被观察者。

而当ListView显示的数据增加或者改变的时候,我们会调用adapter.notifyDataSetChanged()通知改变。再来看看notifyDataSetChanged()做了什么事情,查看源码(DataSetObservable.java)

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();//通知观察者更新            }        }}
但是mObservers是什么呢?继续追踪:
/** * Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}. * * This abstract class is intended to be subclassed and specialized to maintain * a registry of observers of specific types and dispatch notifications to them. * * @param T The observer type. */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.     * @param observer the observer to register     * @throws IllegalArgumentException the observer is null     * @throws IllegalStateException the observer is already 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); //注册观察者        }    }    ...}

其实mObservers其实是Observable里面的一个成员。然而,到底在什么地方实际进行了onChanged()了?查看源码(AbsListView.java):

public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,       ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,       ViewTreeObserver.OnTouchModeChangeListener,       RemoteViewsAdapter.RemoteAdapterConnectionCallback {        class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {           @Override           public void onChanged() {               super.onChanged();               if (mFastScroller != null) {                  mFastScroller.onSectionsChanged();                }           }        ...       }       ... }
追踪super.onChanged()方法(AdapterView.java):

public abstract class AdapterView<T extends Adapter> extends ViewGroup {     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();//重新布局        }    }}
其中requestLayout()进行重新布局,完成数据更新操作。至此,adapter.notifyDataSetChanged()完成了数据的更新了。

下面,我们看看着一系列过程的类图:

我们看到,真正notifyDataSetChanged()是由AdapterDataSetObserver的onChanged()完成的。ListView继承自AbsListView,而GridView则(GridView.java):

public class GridView extends AbsListView {}

由此,可以断定GridView和ListView师出同门,同样适合上面所述的过程。

当然,如果你想探索的话,也可以研究一下ViewPager.java,看看它是否也是这样的呢?