从RecyclerView的源码了解观察者模式
来源:互联网 发布:我的世界强制附魔js 编辑:程序博客网 时间:2024/04/30 20:35
定义
定义对象之前一种一对多的依赖关系,使得当一个对象改变状态,所有依赖这个对象的对象都会得到通知并且自动更新。
使用场景
- 关联行为场景。ps:关联行为是可拆分的,不是“组合”关系
- 事件多级触发场景
- 跨系统的消息交互场景。比如消息队列事件总线的处理机制
结构和UML图
- Subject:抽象主题,也就是被观察者(Observable)角色,抽象主题角色把所有的观察者的引用保存在一个集合中,每个主题都可以有任意数量的观察者,抽象主题提供一个接口么可以添加/删除观察者对象。
- ConcreteSubject:具体主题,又名具体被观察者,该觉得将有关组状态保存进具体的观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- Observer:抽象观察者,观察者的抽象类,定义了一个更新接口,使得在得到主题的更改通知时来更改自己。
- ConcreteSubject:具体的观察者,实现了抽象观察者角色所定义的更新接口,以便在主题的状态改变时更新自身的状态。
简单示例
我们平时如果订阅了某个平台的博客,在有新的博客时会通过邮件等方式通知我们订阅者。这里我就以这个写一个简单的观察者模式的示例
抽象主题:
//抽象主题角色,Subject:被观察者public abstract class Blog { protected final ArrayList<User> mObservers = new ArrayList(); public void addUser(User user){ mObservers.add(user); } public void removeUser(User user){ mObservers.remove(user); } public void removeAll(){ mObservers.clear(); }}
具体主题:
//具体主题角色,ConcreteSubject:具体被观察者public class ConcreteBlog extends Blog{ public ConcreteBlog() { // TODO Auto-generated constructor stub } public void notifyChanged(String str){ for(int i=mObservers.size()-1;i>=0;i--){ mObservers.get(i).update(str); } }}
抽象观察者:
//抽象观察者角色public abstract class User { public void update(String str) { }}
具体的观察者:
public class ConcreteUser extends User { @Override public void update(String str) { System.out.println(str); }}
Client:
public class Client { public Client() { // TODO Auto-generated constructor stub } public static void main(String[] args) { //创建被观察者 ConcreteBlog blog=new ConcreteBlog(); //创建观察者 ConcreteUser user1=new ConcreteUser(); ConcreteUser user2=new ConcreteUser(); ConcreteUser user3=new ConcreteUser(); //将观察者注册到可观察对象的观察者列表中 blog.addUser(user1); blog.addUser(user2); blog.addUser(user3); blog.notifyChanged("发布博客了,快来看啊!"); }}}
RecyclerView源码中的观察者模式
在使用RecyclerView的时候,我们在每次更新了RecyclerView的数据后通常调用notifyDataSetChanged()方法来更新我们的视图,那么我们就从这里开始,一步步跟进到源码看看RecyclerView的观察者模式是怎么实现的
public static abstract class Adapter<VH extends ViewHolder> { //定义观察者 private final AdapterDataObservable mObservable = new AdapterDataObservable(); private boolean mHasStableIds = false; public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); .........//省略 public void registerAdapterDataObserver(AdapterDataObserver observer) { mObservable.registerObserver(observer); } public void unregisterAdapterDataObserver(AdapterDataObserver observer) { mObservable.unregisterObserver(observer); } //通知所有观察者 public final void notifyDataSetChanged() { mObservable.notifyChanged(); }
由上可知,其实我们的RecyclerView.Adapter本质就是观察者模式,接着下一步我们跟进到notifyDataSetChanged()方法来看看
static class AdapterDataObservable extends Observable<AdapterDataObserver> { public boolean hasObservers() { return !mObservers.isEmpty(); } //调用没一个观察者的onChanged()方法来通知他们被观察者发生了变化 public void notifyChanged() { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } public void notifyItemRangeChanged(int positionStart, int itemCount) { notifyItemRangeChanged(positionStart, itemCount, null); } public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload); } } .......//省略
这样一看,原来就是在AdapterDataObservable.notifyChanged()方法中来遍历所有的观察者,调用他们的onChange()方法,来通知的。我特意还贴出了notifyItemRangeChanged()方法,我们发现都是通过一样的模式去通知观察者的。
这样下来,我们知道了被观察者(Observable)是怎么实现的,现在我们来找找看观察者(Observer)是从哪儿来的呢?
回想一下,平时我们RecyclerView关联数据的时候都是通过调用setAdapter()方法实现的,那我们进去看看
public void setAdapter(Adapter adapter) { // bail out if layout is frozen setLayoutFrozen(false); setAdapterInternal(adapter, false, true); requestLayout(); }
咦?该方法把adapter传进了setAdapterInternal()方法,我们再跟进去看看。其实看到最后调用requestLayout()方法来重绘View我们就知道观察者的注册操作肯定是在上面方法中完成。
//定义在RecyclerView中,RecyclerViewDataObserver继承与AdapterDataObserverprivate final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious, boolean removeAndRecycleViews) { //如果当前已经存在一个adapter了,就先注销这个adapter对象的观察者 if (mAdapter != null) { mAdapter.unregisterAdapterDataObserver(mObserver); mAdapter.onDetachedFromRecyclerView(this); } if (!compatibleWithPrevious || removeAndRecycleViews) { removeAndRecycleViews(); } mAdapterHelper.reset(); final Adapter oldAdapter = mAdapter; mAdapter = adapter; if (adapter != null) { //将观察者注册到Adapter中,实质是注册到AdapterDataObservable中 adapter.registerAdapterDataObserver(mObserver); adapter.onAttachedToRecyclerView(this); } if (mLayout != null) { mLayout.onAdapterChanged(oldAdapter, mAdapter); } //数据更新操作 mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); mState.mStructureChanged = true; //将之前的所有已知的itemveiw设置invalid(ViewHolder标志位FLAG_UPDATE | FLAG_INVALID) markKnownViewsInvalid(); }
通过以上的代码我们知道,在设置setAdapter的时候会构建一个RecyclerViewDataObserver,也就是我们的观察者(RecyclerViewDataObserver),然后将它注册到被观察者(RecyclerViewDataObserver)中。
我们找到了被观察者是怎么和观察者关联的,但是具体RecyclerViewDataObserver是什么东西呢?内部是怎么闪现的呢?我们继续研究研究,上面代码中我提到RecyclerViewDataObserver继承与AdapterDataObserver,那我们先来看看他的父类
public static abstract class AdapterDataObserver { public void onChanged() { // Do nothing } public void onItemRangeChanged(int positionStart, int itemCount) { // do nothing } public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { // fallback to onItemRangeChanged(positionStart, itemCount) if app // does not override this method. onItemRangeChanged(positionStart, itemCount); } public void onItemRangeInserted(int positionStart, int itemCount) { // do nothing } public void onItemRangeRemoved(int positionStart, int itemCount) { // do nothing } public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { // do nothing } }
基本父类都是空方法,没有具体的实现。我们在来看看RecyclerViewDataObserver是如何重写父类的onChanged()方法的
private class RecyclerViewDataObserver extends AdapterDataObserver { RecyclerViewDataObserver() { } @Override public void onChanged() { assertNotInLayoutOrScroll(null); mState.mStructureChanged = true; // setDataSetChangedAfterLayout(); if (!mAdapterHelper.hasPendingUpdates()) { //重新布局 requestLayout(); } } ......//省略 }
好了。目前我们就到此为止吧(其实后面的我还没去仔细研究),总结一下,当RecyclerView的数据发生变化时,调用Adapter的notifyDataSetChanged()方法,这个方法又会调用AdapterDataObservable的notifyChanged()方法。这个方法又会调用所有观察者的onChanged()方法,在onChanged方法里dui RecyclerView进行重新布局是的RecyclerView刷新界面。一个完整的观察者模式就出来了。
总结
最后我们更加容易懂的一句话来总结:我们在创建Adapter的时候构建了一个RecyclerViewDataObserver,并且在setAdapter()的时候注册进了Adapter(本质是注册到AdapterDataObservable)。在我们调用notifyDataSetChanged()方法的时候,其实就是调用了AdapterDataObservable的notifyChanged()方法,该方法会遍历所有观察者的onChanged()方法,该方法会调用RecyclerView重新布局。(好像这句话比较长哈)
- 从RecyclerView的源码了解观察者模式
- RecyclerView的观察者模式
- 在BaseAdapter源码中了解观察者模式
- 从adapter源码看其中的观察者模式
- 从ListView源码看观察者模式
- Android——RecyclerView下的观察者模式
- 从观察者模式的角度看RxJava
- 观察者设计模式--listView的源码分析
- 源码分析Java的观察者模式
- RecyclerView的深入了解
- 从源码的角度了解AsyncTask
- 从源码了解Volley
- junit源码学习--观察者模式
- java源码实现观察者模式
- Android源码中的观察者模式
- 从观察者模式,简单实现Node的Events模块
- 看JSlider的jdk源码学观察者模式
- Android RecyclerView的简单了解
- weblogic基础知识_简单整理
- 1068. 万绿丛中一点红
- Android 动画-共享元素动画
- 历届试题 分糖果
- 算法设计与应用基础:第十一周
- 从RecyclerView的源码了解观察者模式
- 抽象类的接口
- 嵌入式QT--静态编译
- JAVA JXL API的详细使用
- Android重要知识点解析整理
- java基础--4.常用类-4.Array
- 一维、二维码生成DEMO
- redis3.2.8环境搭建及集群的搭建
- unity接入ios内购