作业三-观察者模式
-
观察者模式简介
- 观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
- 在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
-
观察者模式结构
-
观察者模式包含的角色
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
-
Android中的观察者模式
- android源码中也有很多使用了观察者模式,比如OnClickListener、ContentObserver、android.database.Observable等;还有组件通讯库RxJava、RxAndroid、EventBus;在这里将拿我们最常用的Adapter的notifyDataSetChanged()方法来举例:
当我们用ListView的时候,数据发生变化的时候我们都会调用Adapter的notifyDataSetChanged()方法,这个方法定义在BaseAdaper中,我们来看看BaseAdaper的部分源码:
1 public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { 2 3 //数据集观察者 4 private final DataSetObservable mDataSetObservable = new DataSetObservable(); 5 6 public boolean hasStableIds() { 7 return false; 8 } 9 10 public void registerDataSetObserver(DataSetObserver observer) { 11 mDataSetObservable.registerObserver(observer); 12 } 13 14 public void unregisterDataSetObserver(DataSetObserver observer) { 15 mDataSetObservable.unregisterObserver(observer); 16 } 17 18 /** 19 * 当数据集变化时,通知所有观察者 20 */ 21 public void notifyDataSetChanged() { 22 mDataSetObservable.notifyChanged(); 23 }
BaseAdapter用的是观察者模式,BaseAdapter是具体被观察者,接下来看看mDataSetObservable.notifyChanged():
1 public class DataSetObservable extends Observable<DataSetObserver> { 2 public void notifyChanged() { 3 synchronized(mObservers) { 4 for (int i = mObservers.size() - 1; i >= 0; i--) { 5 mObservers.get(i).onChanged(); 6 } 7 } 8 }
我们看到了mObservers,这就是观察者的集合,这些观察者是在ListView通过setAdaper()设置Adaper时产生的:
1 @Override 2 public void setAdapter(ListAdapter adapter) { 3 if (mAdapter != null && mDataSetObserver != null) { 4 mAdapter.unregisterDataSetObserver(mDataSetObserver); 5 } 6 ... 7 super.setAdapter(adapter); 8 9 if (mAdapter != null) { 10 mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); 11 mOldItemCount = mItemCount; 12 mItemCount = mAdapter.getCount(); 13 checkFocus(); 14 //创建数据观察者 15 mDataSetObserver = new AdapterDataSetObserver(); 16 //注册观察者 17 mAdapter.registerDataSetObserver(mDataSetObserver); 18 19 ... 20 }
接下来看看观察者AdapterDataSetObserver中处理了什么:
1 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { 2 @Override 3 public void onChanged() { 4 super.onChanged(); 5 if (mFastScroller != null) { 6 mFastScroller.onSectionsChanged(); 7 } 8 } 9 10 @Override 11 public void onInvalidated() { 12 super.onInvalidated(); 13 if (mFastScroller != null) { 14 mFastScroller.onSectionsChanged(); 15 } 16 } 17 }
再看看AdapterDataSetObserver的父类AdapterView的AdapterDataSetObserver:
1 class AdapterDataSetObserver extends DataSetObserver { 2 private Parcelable mInstanceState = null; 3 @Override 4 public void onChanged() { 5 mDataChanged = true; 6 mOldItemCount = mItemCount; 7 mItemCount = getAdapter().getCount(); 8 if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null 9 && mOldItemCount == 0 && mItemCount > 0) { 10 AdapterView.this.onRestoreInstanceState(mInstanceState); 11 mInstanceState = null; 12 } else { 13 rememberSyncState(); 14 } 15 checkFocus(); 16 //重新布局 17 requestLayout(); 18 } 19 20 ... 21 22 public void clearSavedState() { 23 mInstanceState = null; 24 } 25 }
我们看到在onChanged()方法中调用了requestLayout()方法来重新进行布局。当ListView的数据发生变化时,我们调用Adapter的notifyDataSetChanged()方法,这个方法又会调用观察者们(AdapterDataSetObserver)的onChanged()方法,onChanged()方法又会调用requestLayout()方法来重新进行布局。
- 通过分析我们得知:
- 通过给setAdapter(adapter)方法进行观察者的注册。
- 被观察者通过notifyDataSetChanged()方法通知观察者进行处理。
- AdapterDataSetObserver继承自AdapterView内部类AdapterDataSetObserver,并交由它来进行AdapterView组件的重新布局。
使用观察者模式,最大的好处就是实现了代码解耦,被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
- 跳转链接: https://github.com/aosp-mirror/platform_frameworks_base/blob/a01c77a499d9037a21b8ea1a5cd1df1a7dea7f25/core/java/android/widget/BaseAdapter.java#L53


浙公网安备 33010602011771号