Android 观察者模式

概念:

定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

四个元素(自我定义):

观察者、被观察者、注册时机、方法调用

两种实现方式:

观察者被动接受消息
1.创建被观察者接口

 public interface Subject{
        public void registerObserver(Observer o);
        public void removeObserver(Observer o);
        public void notifyObservers();
    }

被观察者的实现逻辑

     public class WeatherData implements Subject{

        private ArrayList observers;
        //温度
        private String temperature;
        //湿度
        private String humidity;
        //气压
        private String pressure;

        public WeatherData() {
            observers=new ArrayList();
        }
        /**
         * 订阅
         */
        public void registerObserver(Observer o) {
            observers.add(o);
        }
        /**
         * 取消订阅
         */
        public void removeObserver(Observer o) {
            if(observers.indexOf(o)>=0){
                observers.remove(o);
            }
        }
        /**
         * 通知观察者
         */
        public void notifyObservers() {
            for(Observer o:observers){
                o.update(temperature, humidity, pressure);
            }
        }
        /**
         * 数据改变后,通知观察者
         * @param temperature
         * @param humidity
         * @param pressure
         */
        public void setNewData(String temperature,String humidity,String pressure){
            this.temperature=temperature;
            this.humidity=humidity;
            this.pressure=pressure;
            notifyObservers();
        }
    }

在notifyObservers方法中会遍历观察者集合调用其的update方法,然后传过去变化的值,在观察者中显示。
2.创建观察者接口

 public interface Observer{
        public void update(String temperature,String humidity,String pressure);
    }

3.观察者的实现与注册,每一个观察者的注册时机不同,这里是在实例化观察者的时候注册的

public class CurrentCodition implements Observer {
        private Subject weaterData;

        public CurrentCodition(Subject weaterData) {
            this.weaterData = weaterData;
            weaterData.registerObserver(this);
        }
        @Override
        public void update(String temperature,String humidity,String pressure) {
        //具体实现逻辑
        }
    }

4.调用更新

WeatherData weatherData=new WeatherData();
Observer1 observer1=new Observer1(weatherData);
weatherData.setNewData("10", "20", "30");

观察者主动接受消息
1.被观察者
在上文的基础上添加get方法,为了给观察者提供获得想要数据的方法。

public String getTemperature() {
        return temperature;
    }
    public String getHumidity() {
        return humidity;
    }
    public String getPressure() {
        return pressure;
    }

2.观察者
修改观察者中的update方法,从WeatherData实例中直接获得自己想要的数据,不需要的就不用get了

public void update(Observable o, Object arg) {
        if(o instanceof WeatherData){
            WeatherData data=(WeatherData)o;
            this.humidity=data.getHumidity();
            this.pressure=data.getPressure();
            this.temperature=data.getTemperature();
        }
        System.out.println("数据提取完毕,并已展示");
    }

在Android中的使用

1.setOnClickListener()实现一对一的观察者模式
首先直接看方法里面是怎么一个实现逻辑

 public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

可以发现setOnClickListener()的过程中直接将OnClickListener赋值给了ListenerInfo中的变量,然后这个变量什么时候调用呢,接着看

public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }

可以看到在performClick()方法中直接调用onClick方法,那又是谁调的performClick()方法呢,通过搜索定位到View类中,可以看到以下代码逻辑

public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
        if (isNestedScrollingEnabled()
                && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
                || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
                || action == R.id.accessibilityActionScrollUp
                || action == R.id.accessibilityActionScrollLeft
                || action == R.id.accessibilityActionScrollDown
                || action == R.id.accessibilityActionScrollRight)) {
            if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) {
                return true;
            }
        }

        switch (action) {
            case AccessibilityNodeInfo.ACTION_CLICK: {
                if (isClickable()) {
                    performClick();
                    return true;
                }
            } break;
            case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
                if (isLongClickable()) {
                    performLongClick();
                    return true;
                }
            } break;

代码中用了一个switch条件判断,根据不同的操作执行相应的逻辑,看到这里就应该很清楚,View这个被观察者,监听到状态的变化后,就会去调用注册进来的onClickListener中的onClick观察者方法,完成相应的操作,由于是一对一的监测,所以没有集合的遍历操作。
2.listView实现一对多的观察者模式
先看被观察者的实现方式吧

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

从代码中可以看到BaseAdapter并没有直接继承DataSetObservable(被观察者)类,而是通过组合的方式,作为变量使用的。
然后再看观察者
在listView的父类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;

            checkFocus();
            requestLayout();
        }

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

然后看方法的调用

public void notifyChanged() {
    synchronized(mObservers) {
    for (int i = mObservers.size() - 1; i >= 0; i--) {
            mObservers.get(i).onChanged();
        }
    }
}

每次有数据更新的时候,都会调用这个方法刷新数据,可以看到方法中是遍历一个观察者的集合,然后调用统一的实现方法onChanged()实现数据的刷新。
最后就是注册了,其实每次setAdapter()就是注册的过程,代码就不贴了,感兴趣的小伙伴可以自行查看源码。
!!还是小菜鸟,如若有问题欢迎指出[微笑脸]
喵印~~

你可能感兴趣的:(Android 观察者模式)