设计模式之----观察者模式(Listview刷新原理分析)

一、 定义

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

二、角色

  • 抽象主题角色(Subject)

    抽象主题角色把所有观察者对象的引用保存到一个聚集里(例如ArrayList对象),每个主题都可以有任何数量的观察者。抽象主题提供增加、移除观察者对象的方法。也叫抽象被观察者角色。

  • 具体主题角色(ConcreteSubject)

    在具体主题内部状态改变时,给所有登记过的观察者发出通知。也叫具体被观察者角色。

  • 抽象观察者角色(Observer)

    为所有的具体观察者定义一个更新接口,在得到主题的通知时更新自己。

  • 具体观察者角色(ConcreteObserver)

    实现抽象观察者角色的更新接口,以便在得到主题更改通知时及时更新自身状态。

相关的类图:

这里写图片描述

三、简单代码实现

3.1 创建抽象观察者

/**
 * 抽象观察者角色
 *
 * Created by Administrator on 2017/10/26.
 */

public abstract class Observer {
    public abstract void update(String result);

    protected String name;

    public Observer(String name) {
        this.name = name;
    }
}

3.2 创建具体观察者

/**
 * 具体的观察者
 *
 * Created by Administrator on 2017/10/26.
 */

public class ConcreteObserver extends Observer {
    private static final String TAG = ConcreteObserver.class.getSimpleName();

    public ConcreteObserver(String name) {
        super(name);
    }

    @Override
    public void update(String result) {
        Log.e(TAG,"name:"+name+";"+result);
    }
}

3.3 创建抽象主题(抽象被观察者)

/**
 * 抽象主题角色(抽象被观察者)
 *
 * Created by Administrator on 2017/10/26.
 */

public abstract class Subject {
    private Vector<Observer> vectors = new Vector<Observer>();

    // 注册观察者
    public void attach(Observer observer){
        vectors.add(observer);
    }
    // 反注册观察者
    public void detach(Observer observer){
        if (vectors.contains(observer)){
            vectors.remove(observer);
        }
    }
    //通知所有注册的观察者,状态改变
    public void notifyObserver(String message){
        for(Observer o:vectors){
            o.update(message);
        }
    }

    public abstract void doSomething();
}

3.4 创建具体主题(具体的观察者)

/**
 * Created by Administrator on 2017/10/26.
 */

public class ConcreteSubject extends Subject {
    @Override
    public void doSomething() {
    }
}

3.5 具体调用

ConcreteObserver observer1 = new ConcreteObserver("观察者1");
ConcreteObserver observer2 = new ConcreteObserver("观察者2");
// 创建具体主题(被观察者)
ConcreteSubject concreteSubject = new ConcreteSubject();
// 注册观察者
concreteSubject.attach(observer1);
concreteSubject.attach(observer2);

concreteSubject.notifyObserver("来学习设计模式了");
// 反注册观察者
//        concreteSubject.detach(observer1);
//        concreteSubject.detach(observer2);

执行结果:

10-26 10:34:09.771 1904-1904/com.observerpattern E/ConcreteObserver: name:观察者1;来学习设计模式了
10-26 10:34:09.771 1904-1904/com.observerpattern E/ConcreteObserver: name:观察者2;来学习设计模式了

四、Android中的观察者模式

典型的安卓中使用观察者模式的有:ListView的刷新,BroadcastReceiver。下面以ListView的刷新来分析。

4.1 ListView的刷新都是调用notifyDataSetChanged,具体分析下

Adapter关联了一个被观察者,这里就是被观察者通知观察者,数据更新。

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    // 其他逻辑...

    /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    // 其他逻辑...
}

4.2 notifyChanged内部实现

被观察者内部通知:遍历所有观察者,通知数据刷新

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

4.3 Adapter关联被观察者与观察者与被观察者的注册

setAdapter的代码就不贴了,只贴关键部分

 mDataSetObserver = new AdapterDataSetObserver();
 mAdapter.registerDataSetObserver(mDataSetObserver);

实际上是用Adapter做了一个传递。

public void registerDataSetObserver(DataSetObserver observer) {
    mDataSetObservable.registerObserver(observer);
}

4.4 具体的刷新操作

这里就要分析AdapterDataSetObserver了,因为这是观察者,观察者接收到通知后会进行数据刷新。
先在onChange方法中获取数据个数,然后再去requestLayout,重新布局AdapterViewCompat。

    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 (AdapterViewCompat.this.getAdapter().hasStableIds() && mInstanceState != null
                && mOldItemCount == 0 && mItemCount > 0) {
            AdapterViewCompat.this.onRestoreInstanceState(mInstanceState);
            mInstanceState = null;
        } else {
            rememberSyncState();
        }
        checkFocus();
        requestLayout();
    }

    @Override
    public void onInvalidated() {
        mDataChanged = true;

        if (AdapterViewCompat.this.getAdapter().hasStableIds()) {
            // Remember the current state for the case where our hosting activity is being
            // stopped and later restarted
            mInstanceState = AdapterViewCompat.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;
    }
}

五、总结

5.1 优点

观察者和被观察者是抽象耦合,容易扩展,修改其中一方可以不影响另一方的改变。

5.2 缺点

  • 由于通知是使用的简单循环,有可能某个方法内部出现问题导致阻塞或者异常(改为异步),观察者较多时,效率问题也有待提升。

5.3 使用场景

  • 一个对象状态的更新,需要同步给其他对象时(比如推送的消息列表实时更新、消息数同步增加)
  • 对象仅需要将自己的更新通知给其他对象,而不需要知道其实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值