定义对象以前一种一对多的依赖关系,使得当一个对象改变状态,全部依赖这个对象的对象都会获得通知而且自动更新。java
咱们平时若是订阅了某个平台的博客,在有新的博客时会经过邮件等方式通知咱们订阅者。这里我就以这个写一个简单的观察者模式的示例 抽象主题:设计模式
//抽象主题角色,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();
}
}
复制代码
具体主题:
markdown
// 具体主题角色,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);
}
}
}
复制代码
抽象观察者:
app
// 抽象观察者角色
public abstract class User {
public void update(String str) {
}
}
复制代码
具体的观察者:ide
public class ConcreteUser extends User {
@Override
public void update(String str) {
System.out.println(str);
}
}
复制代码
使用:布局
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("发布博客了,快来看啊!");
}
}}
复制代码
以上内容来摘抄自《Android源码设计模式解析与实战》this
在使用RecyclerView
的时候,咱们在每次更新了RecyclerView
的数据后一般调用notifyDataSetChanged()
方法来更新咱们的视图。那么咱们就从这里开始,到源码看看RecyclerView
的观察者模式是怎么实现的spa
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()
也是经过同样的模式去通知观察者的。code
这样下来,咱们知道了被观察者(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继承与AdapterDataObserver
private 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();
}
复制代码
经过以上的代码咱们知道,在设置setAdapte
r的时候会构建一个RecyclerViewDataObserver
,也就是观察者,而后将它注册到被观察者-AdapterDataObservable
中。 咱们找到了被观察者是怎么和观察者关联的,可是具体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
方法里对RecyclerView
进行从新布局是的RecyclerView
刷新界面。一个完整的观察者模式就出来了。
在建立Adapter
的时候构建了一个RecyclerViewDataObserver
,而且在setAdapter()
的时候将其注册进了Adapter
(本质是注册到AdapterDataObservable
)。在咱们调用notifyDataSetChanged()
方法的时候,其实就是调用了AdapterDataObservable
的notifyChanged()
方法,该方法会遍历全部观察者的onChanged()
方法,该方法会调用RecyclerView
从新布局。