引言
子曰:“温故而知新,可以为师矣。”(《为政》)
近期看公司的项目的整个架构,发现各种回调,有的是走的接口,但是出现比较多的就是Observer ,感觉很熟悉,就是之前熟悉的观察者模式,于是又研究了一下。
什么是观察者模式
这个模式比较好理解,但是应用也非常多。这个文章写的比较好我这边就不继续介绍了,不理解的可以点开看看 https://www.cnblogs.com/luohanguo/p/7825656.html。
为什么用观察者
两个字:解耦。对象之间的耦合越高,维护成本越高。说白了就是不要出现动一个地方的代码导致其他地方出现一大堆BUG的问题。
个人理解
其实要是搞设计一个整体的框架,那么观察者模式还是很好用的。当然这属于架构的搭建。主要是前期的设计。我们的MVP模式其实也有点观察者的意思,上面博客中那个notify()方法之后,他内部实现的就是
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
这里的oserver.update(message),我们跳开观察者模式来看 是不是就是简单的调用了observer里面的一个方法。然后他在他的update()方法中进行了他所需要的操作。MVP中Activity中首先也是先绑定了Prestener,然后调用P层的内部方法,让他在内部进行操作,比如网络请求,比如数据处理,处理完毕之后再通过调用自己绑定的view,通知UI更新。其实刚开始看MVP也觉得一头水,多看了几遍就明白了其实很简单。附上鸿洋的MVP: https://blog.csdn.net/lmj623565791/article/details/46596109。也就是通知别人做一些操作,Android 中的Handler 也有这个意思,你有什么事情了发个handler 切换到主线程 然后开始执行。但是会耦合到一个Activity中。当然handler最主要的功能还是线程的切换。
使用案例
最近研究了一波RecyclerView发现它里面的Adapter 就是用的观察者模式。
public void setAdapter(@Nullable RecyclerView.Adapter adapter) {
this.setLayoutFrozen(false);
this.setAdapterInternal(adapter, false, true);//下面看一下这个SetAdapterInternal()方法
this.processDataSetCompletelyChanged(false);
this.requestLayout();
}
private void setAdapterInternal(@Nullable RecyclerView.Adapter adapter,
boolean compatibleWithPrevious, boolean removeAndRecycleViews) {
if(this.mAdapter != null) {
this.mAdapter.unregisterAdapterDataObserver(this.mObserver);
this.mAdapter.onDetachedFromRecyclerView(this);
}
//省去部分代码....
if(adapter != null) {
adapter.registerAdapterDataObserver(this.mObserver);
adapter.onAttachedToRecyclerView(this);
}
}
以上的代码我们看一下首先是this.mAdapter.unregisterAdapterDataObserver(this.mObserver);解绑定一个Observer 然后下面又进行了Register。将之前的adapter 进行了解绑然后注册了现在这个传过来的Adapter。看一下这个Observer是怎么写的源码中定义了一下这个Observer , private final RecyclerView.RecyclerViewDataObserver mObserver;看一下我们的RecyclerViewDataObserver 这是一个内部类,继承了RecyclerView.AdapterDataObserver ,下面 贴一下两个源码就会发现跟上面那个博客中写的很相似。
AdapterDataObserver
public abstract static class AdapterDataObserver {
public AdapterDataObserver() {
}
public void onChanged() {
}
public void onItemRangeChanged(int positionStart, int itemCount) {
}
public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
this.onItemRangeChanged(positionStart, itemCount);
}
public void onItemRangeInserted(int positionStart, int itemCount) {
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
}
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
}
}
跟上面的博客中的Observer 类似,写出几个接口的方法,下面的 RecyclerViewDataObserver 就跟上面的User是一个意思。也是继续实现里面的内部方法。
RecyclerViewDataObserver
private class RecyclerViewDataObserver extends RecyclerView.AdapterDataObserver {
RecyclerViewDataObserver() {
}
public void onChanged() {
RecyclerView.this.assertNotInLayoutOrScroll((String)null);
RecyclerView.this.mState.mStructureChanged = true;
RecyclerView.this.processDataSetCompletelyChanged(true);
if(!RecyclerView.this.mAdapterHelper.hasPendingUpdates()) {
RecyclerView.this.requestLayout();
}
}
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
RecyclerView.this.assertNotInLayoutOrScroll((String)null);
if(RecyclerView.this.mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
this.triggerUpdateProcessor();
}
}
public void onItemRangeInserted(int positionStart, int itemCount) {
RecyclerView.this.assertNotInLayoutOrScroll((String)null);
if(RecyclerView.this.mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
this.triggerUpdateProcessor();
}
}
......省去部分代码
void triggerUpdateProcessor() {
if(RecyclerView.POST_UPDATES_ON_ANIMATION && RecyclerView.this.mHasFixedSize && RecyclerView.this.mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, RecyclerView.this.mUpdateChildViewsRunnable);
} else {
RecyclerView.this.mAdapterUpdateDuringMeasure = true;
RecyclerView.this.requestLayout();
}
}
}
触发这个接口的方法之后调用triggerUpdateProcessor方法。内部再调用 RecyclerView.this.requestLayout();进行绘制页面。在adapter中调用一下notifyItemRangeInserted(1,1);这个方法然后点进去看一下
public final void notifyItemRangeInserted(int positionStart, int itemCount) {
this.mObservable.notifyItemRangeInserted(positionStart, itemCount);
}
再看看这里到底做的什么 再点进去看看
public void notifyItemRangeInserted(int positionStart, int itemCount) {
for(int i = this.mObservers.size() - 1; i >= 0; --i) {
((RecyclerView.AdapterDataObserver)this.mObservers.get(i)).onItemRangeInserted(positionStart,itemCount);
}
千呼万唤始出来,终于看到了onItemRangeInserted这个方法,这个就是上面的方法了 然后调用triggerUpdateProcessor()再进行UI的重新绘制。这样就完成了一次操作。层层拨开之后发现这个就是一个观察者模式。我们重新来看一下流程:
基本流程就是这样,等等,好像缺了什么,这边只有观察者,那么被观察者呢。我们注册的时候注册上去的都是观察者,我们再去看看代码。回到上面的流程图的第四步,看一下这个mObservables是什么
private final RecyclerView.AdapterDataObservable mObservable = new RecyclerView.AdapterDataObservable();
这边来了一个AdapterDataObservable又是什么,再进去看看。
static class AdapterDataObservable extends Observable<RecyclerView.AdapterDataObserver> {
AdapterDataObservable() {
}
public boolean hasObservers() {
return !this.mObservers.isEmpty();
}
......省了很多代码
public void notifyItemRangeRemoved(int positionStart, int itemCount) {
for(int i = this.mObservers.size() - 1; i >= 0; --i) {
((RecyclerView.AdapterDataObserver)this.mObservers.get(i))
.onItemRangeRemoved(positionStart, itemCount);
}
}
}
方法在这里面这个就相当于上面博客中的WeChat,有动作之后他再去通知后面的观察者。那么我们再看一下流程图:
这里RecycleView中的观察者模式就结束了。撒花。
总结
初看设计模式,原来这个模式是这样的,一个简单的demo跑一下完事,知其然不知其所以然,现在花时间看一下确实这些设计模式都非常的棒,代码看上去非常的整洁,耦合低,我们现在用的比较多的EventBus 就是很显然的一个观察者模式。 EventBus.getDefault().post(new MessageEvent("Hello EventBus!"));发布事件之后那边就可以接收到。Android 中的广播其实也有这个意思。本文通过一个别人写的一个观察者模式的demo(不自己写是因为写出来都差不多,没必要浪费这个时间,上面那写的确实不错),再看一下源码中的一些代码,可以更好的理解一下这个设计模式,还有运用场景。知道原由之后看到一些项目的时候,就不会因为要不停的点进去看怎么操作而浪费时间了,直接看一下大的接口一下子就知道要做什么,下一步要找谁,可以节约不少阅读时间。
网友评论