应用场景
- 当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
优点
- 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
- 易于扩展,对同一主题新增观察者时无需修改原有代码。
缺点
- 依赖关系并未完全解除,抽象主题仍然依赖抽象观察者。
- 使用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
Android 中的源码分析 1
===================================================================
Button button = (Button) findViewById(R.id.button);
//注册观察者
button.setOnClickListener(new View.OnClickListener() {
//观察者实现
@Override
public void onClick(View arg0) {
Log.d("test", "Click button ");
}
});
===================================================================
上面代码中,button就是具体的主题,也就是被观察者;
new 出来的 View.OnClickListenerd 对象就是具体的观察者;
OnClickListener 实际上就是个接口,也就是抽象观察者;通过 setOnClickListener 把观察者注册到被观察者中。
一旦 button 捕获的点击事件,即状态发生变化的时候,就会通过回调注册的 OnClickListener 观察者的 onClick 方法会来通知观察者,Button 状态发生变化。。
==================================================================
public interface OnClickListener {//抽象观察者
void onClick(View v);//只有onClick这个方法
}
//注册观察者
public void setOnClickListener(@Nullable View.OnClickListener l) {
if (!isClickable()) {
setClickable(true);//设置为可点击
}
getListenerInfo().mOnClickListener = l;//把传入的 OnClickListener 对象赋值给了 getListenerInfo().mOnClickListener,即mListenerInfo的mOnClickListener持有OnClickListener对象的引用
}
ListenerInfo getListenerInfo() {//返回ListenerInfo对象,这里是一个单例模式
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
public boolean performClick() {//执行点击事件
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);//执行onClick方法,li.mOnClickListener即OnClickListener对象
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
=======================================================================
Android 中的源码分析 2: Adapter的notifyDataSetChanged()方法
当我们使用 ListView 时,需要更新数据时我们就会调用 Adapter 的 notifyDataSetChanged() 方法,那么我们来看看 notifyDataSetChanged() 的实现原理,这个方法是定义在 BaseAdaper 中,具体代码如下:
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实际上就是使用了观察者模式,BaseAdapter就是具体的被观察者。接下来看看 mDataSetObservable.notifyChanged()的实现
=======================================================================
//数据集被观察者
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
//遍历所有观察者,并调用他们的onChanged()方法
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
//其他代码略
}
=======================================================================
由上面的代码可以看出BaseAdapter实际上就是使用了观察者模式,BaseAdapter就是具体的被观察者。接下来看看 mDataSetObservable.notifyChanged()的实现:
=======================================================================
//数据集被观察者
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
//遍历所有观察者,并调用他们的onChanged()方法
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
//其他代码略
}
=======================================================================
现在我们看到了有观察者的影子,那么这些观察者是从哪里来的呢?实际上这些观察者是在ListView通过setAdaper()设置Adaper时产生的:
=======================================================================
public class ListView extends AbsListView {
//其他代码略
public void setAdapter(ListAdapter adapter) {
//如果已存在Adapter,先注销该Adapter的观察者
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
//其他代码略
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();//获取Adapter中的数据的数量
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();//创建一个数据集观察者
mAdapter.registerDataSetObserver(mDataSetObserver);//注册观察者
//其他代码略
}
}
}
=======================================================================
从上面的代码可以看到,观察者有了,那么这个观察者主要是干什么的呢?
=======================================================================
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();//调用父类的onChanged()方法
if (mFastScroller != null) {
mFastScroller.onSectionsChanged();
}
}
//其他代码略
}
=======================================================================
AdapterDataSetObserver类中的onChanged()方法没看出啥,继续看他父类的onChanged()方法:
=======================================================================
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
//观察者的核心实现
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();//获取Adapter中的数据的数量
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
//重新布局
requestLayout();
}
//其他代码略
}
=======================================================================
最终就是在AdapterDataSetObserver这个类里面的onChanged()方法中实现了布局的更新。
Reference:
https://www.jianshu.com/p/8f32da74cd8b
No comments:
Post a Comment