Android学习之旅Android技术知识Android开发经验谈

观察者设计模式在 RecyclerView 中的应用

2019-04-18  本文已影响2人  TengFeiGo
简单的理解观察者设计模式

观察者设计模式是行为型模式中的一种,它定义了一种一对多的关系,使的一个对象发生改变的同时能够同步修改所有依赖它的对象,在观察者设计模式中有两个比较重要的概念“观察者(Observer)”“被观察者(Observable)”,我们从日常生活中理解它们,被观察者可以看作是微信公众号,观察者也就是订阅了微信公众号的用户,而公众号的信息也只能推送给订阅了此公众号的用户,所以被观察者也就提供了订阅的功能供观察者们来订阅,如果不想接收来自被观察者的信息,取消订阅即可。
在日常开发过程中,如果你的系统中发生的改变需要同步通知给其它的系统,那么此时可以运用到观察者设计模式,在 Android 源码中典型的有 RecyclerView 和 ListView 数据发生改变的同时通知列表界面来刷新界面,带着怎么实现一个简单观察者的疑问,我们首先写一个上文中提到的“微信公众号小功能”。
首先是定义我们的被观察者,即微信公众号,微信公众号有啥功能呢 ? 肯定是订阅、解除订阅以及推送消息的功能,ok .. 首先是定义一个 Observable 来将我们这些最基本的功能封装起来,注意这里的 Observable 和 Observer 都是自定义的不是 JDK 自带的,千万不要混淆了。

/**
 * @param <T> 使用泛型 T 来表示观察者对象,观察者对象实现了 Observer 接口用来规范观察者对象所具备的行为,写法不是固定的,你可以自由发挥
 * @param <M> 使用泛型 M 来表示所传递的消息对象,泛型还不会的需要自行补课去了哈
 */
public class Observable<T extends Observer<M>,M> {

    private List<T> observerList;

    public Observable() {
        observerList = new ArrayList<>();
    }

    /**
     * 用一个集合来维护所有的观察者对象,注册的同时就是将观察者对象添加到集合中管理的过程
     */
    public void register(T t) {
        if (!observerList.contains(t)) {
            observerList.add(t);
        }
    }

    /**
     * 注销的过程就是将从集合中移除的过程
     */
    public void unRegister(T t) {
        if (observerList.contains(t)) {
            observerList.remove(t);
        }
    }

    /**
     * 推送消息给所有注册的观察者
     */
    public void pushInfo(M m) {
        for (T t : observerList) {
            t.update(m);
        }
    }
}

定义观察者接口,其实不用接口也可以不过可能会损失一部分的代码灵活性。

public interface Observer<M> {

    void update(M m);
}
public class Information {

    public String info;

    public Information(String info) {
        this.info = info;
    }
}

到此为止我们的两大主题都有了接下来可以去定义具体的观察者和被观察者了

public class PeopleObserver implements Observer<Information> {
    @Override
    public void update(Information information) {
        System.out.println(" 卡哇伊 我是  "+information.info);
    }
}
/**
 * "微信公众号"具体被观察者对象
 */
public class WXObservable extends Observable<PeopleObserver,Information>{
}
 //定义具体被观察者对象
WXObservable wxObservable = new WXObservable();
//定义观察者对象
PeopleObserver peopleObserver01 = new PeopleObserver();
PeopleObserver peopleObserver02 = new PeopleObserver();
//注册
 wxObservable.register(peopleObserver01);
wxObservable.register(peopleObserver02);
//修改数据
wxObservable.pushInfo(new Information("哈哈"));

最终的测试结果:
卡哇伊 我是 com.example.observer.simple03.PeopleObserver@2503dbd3  哈哈
卡哇伊 我是 com.example.observer.simple03.PeopleObserver@4b67cf4d  哈哈

以上便是观察者模式最简单的实现,可以看到 WXObservable 依赖并管理了一个集合,在这个集合中则是通过“注册”添加到其中的 PeopleObserver 对象,PeopleObserver 中维护了一个 update 方法,用来在接收到数据后操作,WXObservable 推送的过程其实就是遍历所有它维护的 PeopleObserver 对象,并调用 PeopleObserver 的 update 方法,是不是非常像接口回调 ?我自己认为接口回调就是观察者模式的一种体现。

观察者设计模式在 RecyclerView 中的应用

上面简单的介绍了观察者模式的实现,大家应该对这种设计模式有一点基本的概念了,但实际上在 Android 源码中处处体现着设计模式的思想,就比如说 ListView 和 RecyclerView 是如何在数据源更新后去更新 UI 界面的显示的,这次主要看下观察者模式是如何在 RecyclerView 中体现的。

public void setAdapter(@Nullable RecyclerView.Adapter adapter) {
        this.setLayoutFrozen(false);
        this.setAdapterInternal(adapter, false, true);
        this.processDataSetCompletelyChanged(false);
        this.requestLayout();
    }

为了搞清楚数据是怎么通知界面上更新的,我们先从 setAdapter 函数入手,如上代码,还看不出什么东西,方法中只有 setAdapterInternal 方法与 adapter 有点关系,点进去看看。

    private void setAdapterInternal(@Nullable RecyclerView.Adapter adapter, boolean compatibleWithPrevious, boolean removeAndRecycleViews) {
        if (this.mAdapter != null) {
            // 1 看我 看我
            this.mAdapter.unregisterAdapterDataObserver(this.mObserver);
            this.mAdapter.onDetachedFromRecyclerView(this);
        }

         //省略代码
        if (adapter != null) {
            // 2 看我 看我
            adapter.registerAdapterDataObserver(this.mObserver);
            adapter.onAttachedToRecyclerView(this);
        }

        if (this.mLayout != null) {
            this.mLayout.onAdapterChanged(oldAdapter, this.mAdapter);
        }

        this.mRecycler.onAdapterChanged(oldAdapter, this.mAdapter, compatibleWithPrevious);
        this.mState.mStructureChanged = true;
    }

看我代码中的备注,有没有注意到熟悉的地方,一个是解除注册,一个是注册观察者的方法,这些方法封装在 RecyclerView.Adapter 中,所以我们跟着代码看看 adapter 中做了什么处理。

    public abstract static class Adapter<VH extends RecyclerView.ViewHolder> {
        private final RecyclerView.AdapterDataObservable mObservable = new RecyclerView.AdapterDataObservable();
        private boolean mHasStableIds = false;

        public Adapter() {
        }

        @NonNull
        public abstract VH onCreateViewHolder(@NonNull ViewGroup var1, int var2);

        public abstract void onBindViewHolder(@NonNull VH var1, int var2);

        public void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) {
            this.onBindViewHolder(holder, position);
        }

       //省略代码

        public void registerAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
            this.mObservable.registerObserver(observer);
        }

        public void unregisterAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
            this.mObservable.unregisterObserver(observer);
        }

       

        public final void notifyDataSetChanged() {
            this.mObservable.notifyChanged();
        }

        public final void notifyItemChanged(int position) {
            this.mObservable.notifyItemRangeChanged(position, 1);
        }

        public final void notifyItemChanged(int position, @Nullable Object payload) {
            this.mObservable.notifyItemRangeChanged(position, 1, payload);
        }

        public final void notifyItemRangeChanged(int positionStart, int itemCount) {
            this.mObservable.notifyItemRangeChanged(positionStart, itemCount);
        }

        public final void notifyItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
            this.mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
        }

        public final void notifyItemInserted(int position) {
            this.mObservable.notifyItemRangeInserted(position, 1);
        }

        public final void notifyItemMoved(int fromPosition, int toPosition) {
            this.mObservable.notifyItemMoved(fromPosition, toPosition);
        }

        public final void notifyItemRangeInserted(int positionStart, int itemCount) {
            this.mObservable.notifyItemRangeInserted(positionStart, itemCount);
        }

        public final void notifyItemRemoved(int position) {
            this.mObservable.notifyItemRangeRemoved(position, 1);
        }

        public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
            this.mObservable.notifyItemRangeRemoved(positionStart, itemCount);
        }
    }

Adapter 是 RecyclerView 中的一个静态内部类,在其内部实例化了被观察者对象即 AdapterDataObservable ,所以说在初始化 Adapter 对象的时候就已经创建了被观察者 AdapterDataObservable 对象,而在 setAdapter 时其实就是在将 观察者对象 RecyclerViewDataObserver 与 AdapterDataObservable 两者绑定在了一起,RecyclerViewDataObserver 是在构造方法中初始化的,代码我就不贴了,调用 adapter 的 notifyDataSetChanged 方法会回调 AdapterDataObservable 的 notifyChanged 方法。

        public void notifyChanged() {
            for(int i = this.mObservers.size() - 1; i >= 0; --i) {
                ((RecyclerView.AdapterDataObserver)this.mObservers.get(i)).onChanged();
            }

        }

接下来是常规操作,遍历绑定的每一个观察者对象并同时回调它们的 onChanged 方法,AdapterDataObserver 是一个抽象类,所以来看它的具体实现子类 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();
            }

        }
        // 省略代码
    }

依旧只关注它的 onChanged 方法会发现最终回调了 RecyclerView 的 requestLayout 方法,到这里有没有理解呢 ? 其实数据源发生改变并调用 notifyDataSetChanged 方法刷新界面的时候就是利用观察者模式来进行消息传递并最终通知我们的 View 来进行刷新界面的操作。

上一篇下一篇

猜你喜欢

热点阅读