Android设计模式 — 观察者模式

本文深入解析了ListView在Android中如何通过观察者模式实现数据更新,包括adapter.notifyDataSetChanged()的具体实现及GridView适用性分析。

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

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

listView = (ListView) findViewById(R.id.listView);  
adapter = new MyAdapter();//MyAdapter为自定义的Adapter,继承自BaseAdapter
listView.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,看看它是否也是这样的呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值