1.定义
观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
2.实例(订阅杂志)
代码语言:javascript复制/**
* 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
*/
public interface Observer {
/**
* 有更新就推送消息
*/
public void update(String message);
}
/**
* 具体的观察者类,也就是订阅者
*/
public class User implements Observer {
@Override
public void update(String message) {
System.out.println(name "," message "更新了!");
}
// 订阅者的名字
private String name;
public User(String name) {
this.name = name;
}
}
/**
* 抽象被观察者类
*/
public interface Observable {
/**
* 发送杂志
*/
void sendMagazine(String message);
/**
* 添加用户
*/
void addUser(Observer observer);
}
/**
* 杂志社
*/
public class Magazine implements Observable {
private ArrayList<Observer> mUserList = new ArrayList<Observer>();
@Override
public void sendMagazine(String message) {
for(Observer observer : mUserList){
observer.update(message);
}
}
@Override
public void addUser(Observer observer) {
mUserList.add(observer);
}
}
public static void main(String[] args) {
User user1 = new User("ez");
User user2 = new User("111111");
Magazine magazine = new Magazine();
magazine.addUser(user1);
magazine.addUser(user2);
magazine.sendMagazine("杂志1");
//ez,杂志1更新了!
//111111,杂志1更新了!
}
3.源码体现(BaseAdapter的notifyDataSetChanged)
代码语言:javascript复制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();//********************跟踪这个
}
......
}
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
}
mObservers从哪里来?下面的代码显示,是调用了registerObserver方法。该方法在BaseAdapter的registerDataSetObserver调用的
代码语言:javascript复制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);//**********************************
}
}
}
那么registerDataSetObserver又是什么时候调用的呢?下面的代码显示是ListView等控件setAdapter调用的
代码语言:javascript复制 @Override
public void setAdapter(ListAdapter adapter) {
......
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);//**************************在这里
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
int position;
if (mStackFromBottom) {
position = lookForSelectablePosition(mItemCount - 1, false);
} else {
position = lookForSelectablePosition(0, true);
}
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
} else {
mAreAllItemsSelectable = true;
checkFocus();
// Nothing selected
checkSelectionChanged();
}
requestLayout();
}
搞清楚了mObservers从哪里来,接下来就是要明白mObservers.get(i).onChanged();发生了啥?
代码语言:javascript复制public abstract class DataSetObserver {
/**
* This method is called when the entire data set has changed,
* most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
*/
public void onChanged() {
// Do nothing
}
}
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();//************************重新布局,ViewGroup
}
}
4.总结
1.优点 (1)观察者和被观察者之间是抽象耦合,应对业务变化。 (2)增强系统的灵活性和可扩展性。 2.缺点 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。