美文网首页
Android源码中的设计模式-观察者模式

Android源码中的设计模式-观察者模式

作者: 刺客的幻影 | 来源:发表于2018-11-27 17:39 被阅读0次

    事件总线框架大家应该都用过不少,从最开始的otto到Eventbus,再到Rxbus,这些开源框架都应用到了一个经典的设计模式-观察者模式。使用中,最直观的体验就是不用再去写那些繁琐的回调代码,模块和业务之间的耦合度也会极大程度地降低。

    其实在Android源码中,观察者模式的使用无处不在,应用最广泛、典型的要数ListView和RecyclerView中的Adapter了。下面我们从RecyclerView.Adapter的源码中,分析它的观察者模式是如何实现的。

    • 首先从我们经常调用到的notifyDataSetChanged入手,这是一个通知数据改变,刷新界面布局的方法
    public abstract static class Adapter<VH extends ViewHolder> {
            //被观察者
            private final AdapterDataObservable mObservable = new AdapterDataObservable();
            /**
             * 注册观察者,监听数据集的变化
             */
            public void registerAdapterDataObserver(AdapterDataObserver observer) {
                mObservable.registerObserver(observer);
            }
    
            /**
             * 取消注册,不再监听数据集的改变
             */
            public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
                mObservable.unregisterObserver(observer);
            }
    
            /**
             * 通知注册的观察者数据集发生改变
             */
            public final void notifyDataSetChanged() {
                mObservable.notifyChanged();
            }
    }
    
    • 实际调用的是AdapterDataObservable.notifyChanged()
    static class AdapterDataObservable extends Observable<AdapterDataObserver> {
    
            public void notifyChanged() {
                //调用所有观察者的onChanged方法
                for (int i = mObservers.size() - 1; i >= 0; i--) {
                    mObservers.get(i).onChanged();
                }
            }
    }
    
    • 来到AdapterDataObserver中,调用其onChanged方法
     public abstract static class AdapterDataObserver {
            public void onChanged() {
                // Do nothing
            }
        }
    
    • 可以看到上面是一个抽象类,具体实现看其子类RecyclerViewDataObserver,这里就是观察者收到消息通知后的具体实现
    private class RecyclerViewDataObserver extends AdapterDataObserver {
            //上面说到的所有观察者onChanged方法的核心实现
            @Override
            public void onChanged() {
                //确保RecyclerView没有在layout或者滑动状态
                assertNotInLayoutOrScroll(null);
                mState.mStructureChanged = true;
                //被观察者收到数据发生改变后的具体实现
                setDataSetChangedAfterLayout();
                if (!mAdapterHelper.hasPendingUpdates()) {
                    //重新布局RecyclerView组件
                    requestLayout();
                }
            }
    }
    

    其实到这一步观察者模式中事件的通知方式已经实现,想进一步探究是如何实现的可以继续深入,看看setDataSetChangedAfterLayout()方法

    • 那么问题来了,这里的观察者们是在哪里注册的呢?找到RecyclerView的setAdapter()方法
    public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
         public void setAdapter(Adapter adapter) {
            // bail out if layout is frozen
            setLayoutFrozen(false);
            //具体实现
            setAdapterInternal(adapter, false, true);
            requestLayout();
          }
    
    • 这里也只是包了一层,修改了状态,具体的实现看setAdapterInternal(adapter, false, true),注意关键点adapter.registerAdapterDataObserver(mObserver);
    private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
                boolean removeAndRecycleViews) {
            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.registerAdapterDataObserver(mObserver);
                adapter.onAttachedToRecyclerView(this);
            }
            if (mLayout != null) {
                mLayout.onAdapterChanged(oldAdapter, mAdapter);
            }
            mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
            mState.mStructureChanged = true;
            setDataSetChangedAfterLayout();
        }
    
    • 继续探究RecyclerView中registerAdapterDataObserver的具体实现
    public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
         public void registerAdapterDataObserver(AdapterDataObserver observer) {
                mObservable.registerObserver(observer);
         }
    }
    
    • 看一下mObservable是什么
    public abstract class Observable<T> {
        //用来存放观察者们的集合
        protected final ArrayList<T> mObservers = new ArrayList<T>();
        //观察者的注册,也就是加入到上面的集合中
        public void registerObserver(T observer) {
            if (observer == null) {
                throw new IllegalArgumentException("The observer is null.");
            }
            synchronized(mObservers) {
                if (mObservers.contains(observer)) {
                    throw new IllegalStateException("Observer " + observer + " is already registered.");
                }
                mObservers.add(observer);
            }
        }
        //反注册,也就是从上面的集合取出来
        public void unregisterObserver(T observer) {
            if (observer == null) {
                throw new IllegalArgumentException("The observer is null.");
            }
            synchronized(mObservers) {
                int index = mObservers.indexOf(observer);
                if (index == -1) {
                    throw new IllegalStateException("Observer " + observer + " was not registered.");
                }
                mObservers.remove(index);
            }
        }
        //反注册所有
        public void unregisterAll() {
            synchronized(mObservers) {
                mObservers.clear();
            }
        }
    }
    

    到此,我们就知道了观察者们是在RecyclerView的setAdapter的调用过程中被注册的。总的看来,观察者模式的实现原理是维护一个集合,添加或删除集合元素实现观察者的注册与反注册,遍历集合,调用元素的方法实现消息的推送

    相关文章

      网友评论

          本文标题:Android源码中的设计模式-观察者模式

          本文链接:https://www.haomeiwen.com/subject/ccojfqtx.html