从RecyclerView的源码了解观察者模式

观察者模式

定义对象以前一种一对多的依赖关系,使得当一个对象改变状态,全部依赖这个对象的对象都会获得通知而且自动更新。java

使用场景

  • 关联行为场景。关联行为是可拆分的,不是“组合”关系
  • 事件多级触发场景
  • 跨系统的消息交互场景。好比消息队列事件总线的处理机制

结构和UML图

观察者模式UML.jpg

  • 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();
	}
}

复制代码

具体主题:
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的时候,咱们在每次更新了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();
    }
复制代码

经过以上的代码咱们知道,在设置setAdapter的时候会构建一个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的数据发生变化时,调用AdapternotifyDataSetChanged()方法,这个方法又会调用AdapterDataObservablenotifyChanged()方法。这个方法又会调用全部观察者的onChanged()方法,在onChanged方法里对RecyclerView进行从新布局是的RecyclerView刷新界面。一个完整的观察者模式就出来了。

总结

在建立Adapter的时候构建了一个RecyclerViewDataObserver,而且在setAdapter()的时候将其注册进了Adapter(本质是注册到AdapterDataObservable)。在咱们调用notifyDataSetChanged()方法的时候,其实就是调用了AdapterDataObservablenotifyChanged()方法,该方法会遍历全部观察者的onChanged()方法,该方法会调用RecyclerView从新布局。

相关文章
相关标签/搜索