博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 中的监听器模式与观察者模式
阅读量:5262 次
发布时间:2019-06-14

本文共 11131 字,大约阅读时间需要 37 分钟。

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里的一个内部类( ),具体我们查看下代码:

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

        }

    }

转载于:https://www.cnblogs.com/jerryxing/archive/2012/04/08/2438085.html

你可能感兴趣的文章
Java 序列化
查看>>
Java 时间处理实例
查看>>
Java 多线程编程
查看>>
Java 文件操作
查看>>
Java 数组实例
查看>>
Java 方法实例
查看>>
Java 异常处理
查看>>
Java 目录
查看>>
Java 数据结构
查看>>
MYSQL5.7.24编译安装
查看>>
mysql启动过程
查看>>
应用Python来计算排列中的逆序数个数
查看>>
2017前端面试题总结
查看>>
Http GetPost网络请求
查看>>
SWIFT国际资金清算系统
查看>>
Sping注解:注解和含义
查看>>
站立会议第四天
查看>>
如何快速掌握一门技术
查看>>
利用AMPScript获取Uber用户数据的访问权限
查看>>
vagrant 同时设置多个同步目录
查看>>