ListView观察者模式的应用

ListView观察者模式的应用
摘要由CSDN通过智能技术生成

ListView – 观察者模式的应用

文章开头先贴下另外几篇设计模式的分析,感兴趣的可以看下:
设计模式-简单说明
ListView适配器模式的应用
AsyncTask模板模式的应用
ListView桥接模式的应用
我们先简单的了解一下观察者模式的含义:在我的理解中,观察者模式就是观察者对被观察者高度敏感,一旦被观察者状态发生变化,观察者马上根据新状态刷新自身。在java的观察者模式经典实现中,是通过在被观察者中注册观察者(简单来说就是被观察者持有所有观察者的引用),一旦被观察者状态发生变化,就遍历所有观察者,调用它们的刷新方法。

我们现在以ListView中观察者模式的应用为例,先放一张基于观察者模式的UML类图(新手,如果有错误,还望指出勿喷):
这里写图片描述
先简单的理一下关系,ListView持有一个ListAdapter引用,BaseAdapter为其实现类,我们是以使用BaseAdapter为例,所以这里你也可以理解为就是BaseAdapter,在BaseAdapter中定义有一个final类型的DataSetObservable的被观察者对象,当我们调用setAdapter时会调用DataSetObservable实例的注册观察者对象,这里的观察者对象可以理解为ListView(AdapterDataSetObserver为AbsListView的内部类),这样Adapter就成了被观察者,ListView变成了观察者(数据被观察,View观察)

现在我们进入源码详细分析一下具体实现,大家都知道ListView的经典桥段 mAdapter.notifyDataSetChange(),一旦调用了这个方法,就会刷新界面上的UI效果,那么它到底是怎么实现的呢,我们用的Adapter一般都是继承自BaseAdapter,notifyDataSetChanged()也是定义在BaseAdapter中的,我们来看一下BaseAdapter中相应的源码:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {

    private final DataSetObservable mDataSetObservable = new DataSetObservable();

...
   /**
    * 调用被观察者注册观察者
    */
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

   /**
    * 调用被观察者注销观察者
    */
    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    /**
     * 通知数据状态发生变化
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    ...
}

在BaseAdapter中notifyDataSetChanged的实现看起来也没啥,就一句,我们看下mDataSetObservable的定义吧:

public class DataSetObservable extends Observable<DataSetObserver> {

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

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

我们看见其实就两个方法:

  1. notifyChanged通知状态发生改变,观察者需要刷新状态
  2. notifyInvalidated通知被观察者数据无效作废

而mObservers则是它的基类定义的一个保存观察者的集合,我们简单过一下基类的定义:

public abstract class Observable<T> {

    /**
     * 观察者集合的定义
     */
    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();
        }
    }
}

好了,被观察者就这么点东西,我们已经理清了,那我们该看看观察者在哪呢,它是什么时候被注册的,在通知刷新的时候又做了一些什么操作呢?我们使用ListView的时候设置适配器是必不可少的,适配器的功能除了适配数据成View之外,还注册了观察者,我们看下setAdapter的具体实现:

@Override
public void setAdapter(ListAdapter adapter) {
  if (mAdapter != null && mDataSetObserver != null) {
    //这里是防止重复注册,所以会把之前的观察者先注销
    mAdapter.unregisterDataSetObserver(mDataSetObserver);
  }

  ...

    //可以看见这里创建一个观察者,然后调用Adapter的注册方法。
    mDataSetObserver = new AdapterDataSetObserver();
    mAdapter.registerDataSetObserver(mDataSetObserver);
}

现在观察者和被观察者已经联系起来了,我们看下,观察者的onChanged都做了些啥,从而实现UI的刷新。从上面我们看见观察者对象对AdapterDataSetObserver实例,我们看下AdapterDataSetObserver的onChanged方法做了什么:

@Override
public void onChanged() {
  super.onChanged();
  if (mFastScroll != null) {
    mFastScroll.onSectionsChanged();
  }
}

在这里调用了父类的onChanged方法,看下AdapterDataSetObserver的父类AdapterView.AdapterDataSetObserver中onChanged都做了一些什么操作:

 @Override
public void onChanged() {
  ...

  //刷新界面
  requestLayout();
}

在父类的onChanged方法中我们看见了观察者会调用熟悉的requestLayout方法来刷新界面.这样一条线就连起来了。

这篇文章关于观察者模式的分析就到这里了,如果有什么不足的地方,希望大家指出,多多交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值