观察者设计模式在Android开发中的应用

1. 模式定义

定义对象间一种一对多的依赖关系,每当一个对象改变状态时,则所有依赖于它的对象都会
得到通知并被自动更新。

2. Android 源码中的观察者模式应用

在 Android 的源码中,我们接触比较多的应该是 RecyclerView 和 ListView 了,和其搭配使用的 Adapter,有 刷新列表的 notifyDataSetChanged() 方法,那么,该方法是怎样刷新列表的呢?
首先我们要知道,观察者模式被观察者主要涉及三个操作:注册(添加)观察者、反注册观察者、通知观察者更新。
那 RecyclerView 是什么时候执行上述操作的呢?

RecyclerView.java

public void setAdapter(Adapter adapter) {
        // bail out if layout is frozen
        setLayoutFrozen(false);
        setAdapterInternal(adapter, false, true);
        requestLayout();
    }
    
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) {
            // 1. 看到此处
            adapter.registerAdapterDataObserver(mObserver);
            adapter.onAttachedToRecyclerView(this);
        }
        if (mLayout != null) {
            mLayout.onAdapterChanged(oldAdapter, mAdapter);
        }
        mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
        mState.mStructureChanged = true;
        setDataSetChangedAfterLayout();
    }

在上面的代码 adapter.registerAdapterDataObserver(mObserver); 中,可以看到这就是注册观察者了,此方法属于 RecyclerView 内部类 Adapter

public abstract static class Adapter<VH extends ViewHolder> {
    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(); 方法,那么此方法又做了什么工作呢?

RecyclerView 内部类 Adapter

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

RecyclerView 内部类 AdapterDataObservable

static class AdapterDataObservable extends Observable<AdapterDataObserver> {
       
        public void notifyChanged() {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
        
}

RecyclerView 内部类 AdapterDataObserver

public abstract static class AdapterDataObserver {
        public void onChanged() {
            // Do nothing
        }
        
}

还记得上面我们注册的方法入的参数吗?就是 一个 AdapterDataObserver 对象

adapter.registerAdapterDataObserver(mObserver);

那么,这个 mObserver 是何物?

private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

RecyclerView 内部类 RecyclerViewDataObserver

private class RecyclerViewDataObserver extends AdapterDataObserver {
        RecyclerViewDataObserver() {
        }

        @Override
        public void onChanged() {
            assertNotInLayoutOrScroll(null);
            mState.mStructureChanged = true;

            setDataSetChangedAfterLayout();
            if (!mAdapterHelper.hasPendingUpdates()) {
                requestLayout();
            }
        }
        
}

在此处,RecyclerView 会 requestLayout 等操作把列表给更新过来。

以上就是 RecyclerView 刷新列表的源码分析了,使用了观察者设计模式,对此,我们也可以使用该模式去处理一些有观察和被观察关系的场景。

3. 以公众号推送为例介绍观察者设计模式的精简用法

观察者:观察者需要被 push

观察者具有的操作接口

public interface IWXUser {
    public void push(String article);
}

观察者

public class WXUser implements IWXUser {

    private String name;

    public WXUser(String name) {
        this.name = name;
    }

    @Override
    public void push(String article) {
        System.out.println(name + " 收到了一篇文章:" + article);
    }
}

被观察者:各种公众号

public class WXPublicObservable {
    // 所有订阅的用户(公众号用户)
    public List<IWXUser> mWXUsers;

    public WXPublicObservable(){
        mWXUsers = new ArrayList<>();
    }

    /**
     * 订阅
     */
    public void register(IWXUser wxUser){
        mWXUsers.add(wxUser);
    }

    /**
     * 取消订阅
     * @param wxUser
     */
    public void unregister(IWXUser wxUser){
        mWXUsers.remove(wxUser);
    }

    /**
     * 更新文章
     * @param article
     */
    public void update(String article){
        // 推送文章更新
        for (IWXUser wxUser : mWXUsers) {
            wxUser.push(article);
        }
    }
}

具体的被观察者

public class WXxxxObservable extends WXPublicObservable {
    private String article;

    public String getArticle() {
        return article;
    }

    public void setArticle(String article) {
        this.article = article;
        // 通知更新,推送给微信用户
        update(article);
    }
}
3. 使用介绍
public class Client {
    public static void main(String[] args){
        // 微信公众号 - 具体的被观察者 - xxx
        WXxxxObservable WXxxxObservable = new WXxxxObservable();

        // 微信公众号 - 具体的观察者 vegen 和 小明同学
        WXUser vegen = new WXUser("vegen");
        WXUser xiaoming = new WXUser("小明同学");

        // 微信公众号 - 用户订阅公众号
        WXxxxObservable.register(vegen);
        WXxxxObservable.register(xiaoming);

        // 微信公众号 - 推送文章
        WXxxxObservable.setArticle("我是文章巴拉巴拉1");

        // 微信公众号 - 用户取消订阅公众号
        WXxxxObservable.unregister(vegen);

        // 微信公众号 - 推送文章
        WXxxxObservable.setArticle("我是文章巴拉巴拉2");
    }

}

vegen 和 小明同学 都能收到 文章巴拉巴拉1 的提示,vegen 后面取消了订阅,就只有 小明同学收到了 文章巴拉巴拉2 的提示。

发布了52 篇原创文章 · 获赞 15 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览