Android源码中的观察者模式
2016-08-23 23:57
288 查看
工作这么久,看过这么多别人的技术博客,还没有在自己的账号上写点什么,实在惭愧。与其说要把自己的经验写出来给大家分享,不如说我想记录一下此刻自己的所思所得,以便日后查看。
早在本科时期就接触过一本书叫《大话设计模式》。因为当时代码量几乎为零,因此对设计模式并没有多少认识。现在出去面试经常被问到设计模式,自己写Android代码时也遇到一些常见模式,今天想要记录一下这几天研究的观察者模式。
1 JDK源码中的观察者模式
不管是在《大话设计模式》,还是GoF的《设计模式》,还是别的关于设计模式的经典书籍,抑或是在各类技术博客,大家可以轻易地找到关于观察者模式的定义和示例。因此观察者模式的概念和基本使用不是本文的讨论重点。重点是,观察者模式的使用是如此的广泛,以至于JDK源码中已为该模式提供java.util.Observable基类和java.util.Observers接口。
JDK中的观察者模式的使用如
4000
图所示:Student类实现Observer接口,通过addObserver方法注册到Teacher的观察者列表中去;而Teacher类继承自Observable基类,当Teacher发布消息(publishMessage)时调用notifyObservers()方法,遍历观察者列表中的所有Student,调用他们的update方法;于是Teacher中的message传递到了每个Student中。
JDK中的Observable基类和Observer接口为我们的简单使用观察者模式提供了方便,但它有一个非常明显的缺点:为了使用观察者模式,需要让Teacher继承Observable这个基类,但是Teacher可能已经继承了Person类,而Java又是单继承,不能同时再继承Observable类。解决这个矛盾的思路有两种:一是自定义观察者模式,将add、delete、notify等方法写进Teacher类;二是使用代理模式,在Teacher中维护一个Observable类的对象,并且实现同名的方法,类似如下代码。
其实翻看Android源码,发现Android并没有使用JDK的Observable基类和Observer接口。Instead,Android定义了一个android.database.Observable<T>抽象类,其中T是Oberver type。Observable抽象类中只有registerObserver、unregisterObserver和unregisterAll三个抽象方法,notify的操作需要子类自己定义。与JDK中Observer接口相对应的是DataSetObserver抽象类,里面有onChanged和onValidated两个抽象方法。notify方法、DataSetObserver类、onChanged方法,是不是想到了什么东西?对,setDataSetChanged()!是不是很熟悉?
2.1 ListView源码中的观察者模式
在使用ListView时,数据改变后,我们会手动去调用ListView对应的adapter的setDataSetChanged()方法来通知ListView更新UI。换一种说法,ListView的UI是观察者,ListView对应的adapter中的数据是被观察者,ListView通过注册一个观察者到adapter中,以实现监听adapter的数据变化的目的。经过刨祖坟一般的Ctrl+鼠标左键之后,画出如下UML类图。图中可以看到,ListView注册到adapter中的观察者叫AdapterDataSetObserver,定义在ListView的父类AbsListview中。它又继承自AbsListView的父类AdapterView类中的同名AdapterDataSetObserver。AdapterView.AdapterDataSetObserver最终继承自DataSetObserver抽象类。
细看左下角的BaseAdapter并不是继承Observable,而是拥有DataSetObservable的一个对象,并且包装一下DataSetObservable的方法,对外提供拥有类似方法名的方法,比如
于是我们手动调用adapter的notifyDataSetChanged方法的时候,最终会调到AdapterView.AdapterDataSetObserver的onChanged方法,通过requestLayout()去更新ListView的UI。
由于最近使用RecyclerView代替ListView,所以把RecyclerView中的观察者模式的实现源码也挖出来了,详见下图,与ListView类似。
参考书目:
《大话设计模式》程杰 著
《Android源码设计模式解析与实战》何红辉/关爱民 著
早在本科时期就接触过一本书叫《大话设计模式》。因为当时代码量几乎为零,因此对设计模式并没有多少认识。现在出去面试经常被问到设计模式,自己写Android代码时也遇到一些常见模式,今天想要记录一下这几天研究的观察者模式。
1 JDK源码中的观察者模式
不管是在《大话设计模式》,还是GoF的《设计模式》,还是别的关于设计模式的经典书籍,抑或是在各类技术博客,大家可以轻易地找到关于观察者模式的定义和示例。因此观察者模式的概念和基本使用不是本文的讨论重点。重点是,观察者模式的使用是如此的广泛,以至于JDK源码中已为该模式提供java.util.Observable基类和java.util.Observers接口。
JDK中的观察者模式的使用如
4000
图所示:Student类实现Observer接口,通过addObserver方法注册到Teacher的观察者列表中去;而Teacher类继承自Observable基类,当Teacher发布消息(publishMessage)时调用notifyObservers()方法,遍历观察者列表中的所有Student,调用他们的update方法;于是Teacher中的message传递到了每个Student中。
JDK中的Observable基类和Observer接口为我们的简单使用观察者模式提供了方便,但它有一个非常明显的缺点:为了使用观察者模式,需要让Teacher继承Observable这个基类,但是Teacher可能已经继承了Person类,而Java又是单继承,不能同时再继承Observable类。解决这个矛盾的思路有两种:一是自定义观察者模式,将add、delete、notify等方法写进Teacher类;二是使用代理模式,在Teacher中维护一个Observable类的对象,并且实现同名的方法,类似如下代码。
public void addObserver(Observer observer){ mObservable.addObserver(observer); } 此处不展开讨论了,Android源码中的观察者就是采用类似第二种思路的方法。2 Android源码中的观察者模式
其实翻看Android源码,发现Android并没有使用JDK的Observable基类和Observer接口。Instead,Android定义了一个android.database.Observable<T>抽象类,其中T是Oberver type。Observable抽象类中只有registerObserver、unregisterObserver和unregisterAll三个抽象方法,notify的操作需要子类自己定义。与JDK中Observer接口相对应的是DataSetObserver抽象类,里面有onChanged和onValidated两个抽象方法。notify方法、DataSetObserver类、onChanged方法,是不是想到了什么东西?对,setDataSetChanged()!是不是很熟悉?
2.1 ListView源码中的观察者模式
在使用ListView时,数据改变后,我们会手动去调用ListView对应的adapter的setDataSetChanged()方法来通知ListView更新UI。换一种说法,ListView的UI是观察者,ListView对应的adapter中的数据是被观察者,ListView通过注册一个观察者到adapter中,以实现监听adapter的数据变化的目的。经过刨祖坟一般的Ctrl+鼠标左键之后,画出如下UML类图。图中可以看到,ListView注册到adapter中的观察者叫AdapterDataSetObserver,定义在ListView的父类AbsListview中。它又继承自AbsListView的父类AdapterView类中的同名AdapterDataSetObserver。AdapterView.AdapterDataSetObserver最终继承自DataSetObserver抽象类。
细看左下角的BaseAdapter并不是继承Observable,而是拥有DataSetObservable的一个对象,并且包装一下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(); }上文提到,ListView通过注册一个观察者到adapter中以实现监听adapter中数据集的变化,那么注册的时机是什么呢?继续挖祖坟,找到ListView的setAdapter方法,此方法定义在ListView的爷爷类AdapterView中,这里是Override父类方法。当ListView绑定adapter时,先解注册以前的观察者(如果有的话),然后再new一个新的AdapterDataSetObserver并且注册到adapter中去。
@Override public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { <strong>mAdapter.unregisterDataSetObserver(mDataSetObserver);</strong> } //...此处省略部分代码 if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); <strong> mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);</strong> mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); //...此处省略部分代码} else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); }
于是我们手动调用adapter的notifyDataSetChanged方法的时候,最终会调到AdapterView.AdapterDataSetObserver的onChanged方法,通过requestLayout()去更新ListView的UI。
@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(); }2.2 RecyclerView中的观察者模式
由于最近使用RecyclerView代替ListView,所以把RecyclerView中的观察者模式的实现源码也挖出来了,详见下图,与ListView类似。
参考书目:
《大话设计模式》程杰 著
《Android源码设计模式解析与实战》何红辉/关爱民 著
相关文章推荐
- Android设计模式系列(2)--SDK源码之观察者模式
- 【进阶android】ListView源码分析——适配器及观察者模式
- Android设计模式系列(2)--SDK源码之观察者模式
- Android进阶系列--源码分析观察者模式在ListView的运用
- Android设计模式系列(2)--SDK源码之观察者模式
- Android源码分析:Android中的设计模式——观察者模式
- Android设计模式系列(2)--SDK源码之观察者模式
- Android设计模式系列(2)--SDK源码之观察者模式
- 通过Android源码分析再探观察者模式(二)
- Android源码学习之观察者模式应用及优点介绍
- Android设计模式源码解析之ListView观察者模式
- 当观察者模式和回调机制遇上Android源码
- 解析 ViewTreeObserver 源码,体会观察者模式、Android消息传递(下)
- Android设计模式系列(2)--SDK源码之观察者模式
- android的观察者模式源码浅析
- 解析 ViewTreeObserver 源码,体会观察者模式、Android消息传递(上)
- Android之观察者模式源码分析(DataSetObserver)
- Android设计模式系列(2)--SDK源码之观察者模式
- Android源码学习之观察者模式应用
- Android设计模式源码解析之ListView观察者模式