• Android 中的监听器模式与观察者模式


    1、   观察者模式与监听器机制

    1.1 观察者模式

    1.2 监听器(Listener)机制

    代码的基本框架:

    * 被监控着

    package com.wonders.group;

    import java.util.Collection;

     

    public class ModelTie {

        private Collection<Object> dataSet;

     

        public interface DataSetSupervioer {

            public void onChange();

        }

     

        private DataSetSupervioer dataSetChangeListener;

     

        public void setDataSetChangeListener(DataSetSupervioer dataSetChangeListener) {

            this.dataSetChangeListener = dataSetChangeListener;

        }

     

        public void notifyDataSetChange() {

            if (null != dataSetChangeListener) {

                dataSetChangeListener.onChange();

            }

        }

       

        public Collection<Object> getDataSet() {

            return dataSet;

        }

     

        public ModelTie setDataSet(Collection<Object> dataSet) {

            this.dataSet = dataSet;

            this.notifyDataSetChange(); // 数据设置完毕要通知监听器进行更新操作    

            return this;

        }

    }

    * 监控者

    package com.wonders.group;

    import java.util.Collection;

    import java.util.Iterator;

     

    import com.wonders.group.ModelTie.DataSetSupervioer;

     

    public class PresentationTie {

        private ModelTie model;

     

        public PresentationTie() {

            super();

           

            // 添加监听器

            model.setDataSetChangeListener(new DataSetSupervioer() {

                public void onChange() {

                    // 填写一些前置操作,如更新数据

                    DisplayModel(); // 重新绘制

                    // 填写一些后置操作,如更新状态

                }

            });

        }

     

        public void DisplayModel() {

            Collection<Object> collection = model.getDataSet();

            if (collection != null) {

                for (Iterator iterator = collection.iterator(); iterator.hasNext();) {

                    System.out.println(((Object) iterator.next()).toString());

                    // 其他等等操作

                }

            }

        }

     

        public ModelTie getModel() {

            return model;

        }

     

        public void setModel(ModelTie model) {

            this.model = model;

        }

    }

    2、   ArrayAdapter的观察者实现机制

    以下仅罗列关键代码:

    public class ArrayAdapter<T> extends BaseAdapter implements Filterable {

     

    private boolean mNotifyOnChange = true;

        /**

         * Adds the specified object at the end of the array.

         */

        public void add(T object) {

            if (mOriginalValues != null) {

                synchronized (mLock) {

                    mOriginalValues.add(object);

                    if (mNotifyOnChange) notifyDataSetChanged();

                }

            } else {

                mObjects.add(object);

                if (mNotifyOnChange) notifyDataSetChanged();

            }

        }

     

        /**

         * Inserts the specified object at the specified index in the array.

         */

        public void insert(T object, int index) {

            if (mOriginalValues != null) {

                synchronized (mLock) {

                    mOriginalValues.add(index, object);

                    if (mNotifyOnChange) notifyDataSetChanged();

                }

            } else {

                mObjects.add(index, object);

                if (mNotifyOnChange) notifyDataSetChanged();

            }

        }

     

        /**

         * Removes the specified object from the array.

         */

        public void remove(T object) {

            if (mOriginalValues != null) {

                synchronized (mLock) {

                    mOriginalValues.remove(object);

                }

            } else {

                mObjects.remove(object);

            }

            if (mNotifyOnChange) notifyDataSetChanged();

        }

     

        /**

         * Remove all elements from the list.

         */

        public void clear() {

            if (mOriginalValues != null) {

                synchronized (mLock) {

                    mOriginalValues.clear();

                }

            } else {

                mObjects.clear();

            }

            if (mNotifyOnChange) notifyDataSetChanged();

        }

     

        /**

         * Sorts the content of this adapter using the specified comparator.

         */

        public void sort(Comparator<? super T> comparator) {

            Collections.sort(mObjects, comparator);

            if (mNotifyOnChange) notifyDataSetChanged();

        }

     

        @Override

        public void notifyDataSetChanged() {

            super.notifyDataSetChanged();   // 关键代码,这个notifyDataSetChanged()是从父类BaseAdapter继承过来的,所以看看在父类中它干了些什么

            mNotifyOnChange = true;

    }

    }

    /**

     * Common base class of common implementation for an {@link Adapter} that can be

     * used in both {@link ListView} (by implementing the specialized

     * {@link ListAdapter} interface} and {@link Spinner} (by implementing the

     * specialized {@link SpinnerAdapter} interface.

     */

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {

        private final DataSetObservable mDataSetObservable = new DataSetObservable();

     

        public void registerDataSetObserver(DataSetObserver observer) {

    这对方法用来注册或注销

    观察ArrayAdapter的观察者的

     

            mDataSetObservable.registerObserver(observer);

        }

     

        public void unregisterDataSetObserver(DataSetObserver observer) {

            mDataSetObservable.unregisterObserver(observer);

        }

     

        /**

         * Notifies the attached View that the underlying data has been changed

         * and it should refresh itself.

         */

        public void notifyDataSetChanged() {

            mDataSetObservable.notifyChanged();  // 关键代码:说明调的是成员变量mDataSetObservable的方法,所以进入DataSetObservable看看具体是如何操作的

        }

     

        public void notifyDataSetInvalidated() {

            mDataSetObservable.notifyInvalidated();

        }

    }

    package android.database;

     

    /**

     * A specialization of Observable for DataSetObserver that provides methods for

     * invoking the various callback methods of DataSetObserver.

     */

    public class DataSetObservable extends Observable<DataSetObserver> {

        /**

         * Invokes onChanged on each observer. Called when the data set being observed has

         * changed, and which when read contains the new state of the data.

         */

        public void notifyChanged() {

            synchronized(mObservers) {

                for (DataSetObserver observer : mObservers) { // 这里的mObservers是哪来的呢?继续追踪,但首先可以判断是来自Observable<DataSetObserver>的。进入看看

                    observer.onChanged();

                }

            }

        }

     

        /**

         * Invokes onInvalidated on each observer. Called when the data set being monitored

         * has changed such that it is no longer valid.

         */

        public void notifyInvalidated() {

            synchronized (mObservers) {

                for (DataSetObserver observer : mObservers) {

                    observer.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>();

     

        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();

            }       

        }

    }

    对于DataSetObserver基类,我们也给出代码:

    public abstract class DataSetObserver {

        public void onChanged() {}

        public void onInvalidated() {}

    }

    综合起来分析就是,ArrayAdapter使自己具备被观察的能力的方法是,ArrayAdapter内部有一个private final DataSetObservable mDataSetObservable = new DataSetObservable()的变量,这个变量一方面维护着一个保存观察者的数据结构,另一方面提供registerDataSetObserver(DataSetObserver observer)和unregisterDataSetObserver(DataSetObserver observer)来管理观察自己的对象;而当ArrayAdapter绑定数的据发生变化时,它会调用内部的notifyDataSetChanged()方法,但这个方法最终是调用mDataSetObservable的notifyChanged()方法。在该方法里,该方法会逐一审视有哪些观察者在观察我,然后调用观察者的观察方法onChanged()。

    3、   ListView观察ArrayAdapter的数据集的机制

    通过以上分析可以知道,ListView要实现观察ArrayAdapter,需要将自己注册到ArrayAdapter的DataSetObservable mDataSetObservable里去,注册的方法是调用ArrayAdapter的registerDataSetObserver(DataSetObserver observer)方法。

    那ListView是如何将自己注册上去的呢?具体过程如下:

    public class ListView extends AbsListView {

    /**

         * Sets the data behind this ListView.

         *

         * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},

         * depending on the ListView features currently in use. For instance, adding

         * headers and/or footers will cause the adapter to be wrapped.

         *

         * @param adapter The ListAdapter which is responsible for maintaining the

         *        data backing this list and for producing a view to represent an

         *        item in that data set.

         */

        @Override

        public void setAdapter(ListAdapter adapter) {

            if (null != mAdapter) {

                mAdapter.unregisterDataSetObserver(mDataSetObserver); // 关键的成员变量,继承自AbsListView,等下去看看AbsListView关于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;

            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();

                }

     

                if (mChoiceMode != CHOICE_MODE_NONE &&

                        mAdapter.hasStableIds() &&

                        mCheckedIdStates == null) {

                    mCheckedIdStates = new LongSparseArray<Boolean>();

                }

     

            } else {

                mAreAllItemsSelectable = true;

                checkFocus();

                // Nothing selected

                checkSelectionChanged();

            }

     

            if (mCheckStates != null) {

                mCheckStates.clear();

            }

           

            if (mCheckedIdStates != null) {

                mCheckedIdStates.clear();

            }

     

            requestLayout();

    }

    }

    public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,

            ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,

            ViewTreeObserver.OnTouchModeChangeListener {

     

       /**

         * Should be used by subclasses to listen to changes in the dataset

         */

        AdapterDataSetObserver mDataSetObserver; // mDataSetObserver就是在这里定义的。那我们再看看AdapterDataSetObserver是什么类型的数据,看看当数据发生变化的时候,该类会进行什么样的动作。

     

        /**

         * The adapter containing the data to be displayed by this view

         */

    ListAdapter mAdapter;

    }

    值得注意的是,AdapterDataSetObserver是AdapterView里的一个内部类(http://www.androidjavadoc.com/1.1_r1_src/android/widget/class-use/AdapterView.AdapterDataSetObserver.html ),具体我们查看下代码:

    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;

                checkSelectionChanged();

     

                checkFocus();

                requestLayout();

            }

     

            public void clearSavedState() {

                mInstanceState = null;

            }

        }

    最终调用的代码(from View.class)

        /**

         * Call this when something has changed which has invalidated the

         * layout of this view. This will schedule a layout pass of the view

         * tree.

         */

        public void requestLayout() {

            if (ViewDebug.TRACE_HIERARCHY) {

                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);

            }

     

            mPrivateFlags |= FORCE_LAYOUT;

     

            if (mParent != null && !mParent.isLayoutRequested()) {

                mParent.requestLayout();

            }

        }

  • 相关阅读:
    学完自动化测试,用小技能做了点兼职刷弹幕,小赚10W
    学会这个,助你升值加薪自动化框架之python+selenium+pytest
    我都30岁了,现在做软件测试还来得及吗
    如何从小白成长为技术大牛,阿里测试总监为你梳理成神之路【全套资源分享】
    Google公布编程语言排名,第一竟然是他?
    程序员改行率竟然高达40%,看完我沉默了
    程序员一定要远离这个万恶之源
    自动化测试框架很难吗?我不觉得,不信你看
    三年经验的程序员,为什么能力要强过80%的人
    实验十 团队作业6:团队项目用户验收&Beta冲刺
  • 原文地址:https://www.cnblogs.com/jerryxing/p/2438085.html
Copyright © 2020-2023  润新知