觀察者設(shè)計模式在Android開發(fā)中的應(yīng)用

1. 模式定義

定義對象間一種一對多的依賴關(guān)系,每當(dāng)一個對象改變狀態(tài)時,則所有依賴于它的對象都會
得到通知并被自動更新。

2. Android 源碼中的觀察者模式應(yīng)用

在 Android 的源碼中,我們接觸比較多的應(yīng)該是 RecyclerView 和 ListView 了,和其搭配使用的 Adapter,有 刷新列表的 notifyDataSetChanged() 方法,那么,該方法是怎樣刷新列表的呢?
首先我們要知道,觀察者模式被觀察者主要涉及三個操作:注冊(添加)觀察者、反注冊觀察者、通知觀察者更新。
那 RecyclerView 是什么時候執(zhí)行上述操作的呢?

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 內(nèi)部類 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();
        }
}

當(dāng)我們更新 RecyclerView 數(shù)據(jù)源的時候,執(zhí)行了 adapter.notifyDataSetChanged(); 方法,那么此方法又做了什么工作呢?

RecyclerView 內(nèi)部類 Adapter

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

RecyclerView 內(nèi)部類 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 內(nèi)部類 AdapterDataObserver

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

還記得上面我們注冊的方法入的參數(shù)嗎?就是 一個 AdapterDataObserver 對象

adapter.registerAdapterDataObserver(mObserver);

那么,這個 mObserver 是何物?

private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

RecyclerView 內(nèi)部類 RecyclerViewDataObserver

private class RecyclerViewDataObserver extends AdapterDataObserver {
        RecyclerViewDataObserver() {
        }

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

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

在此處,RecyclerView 會 requestLayout 等操作把列表給更新過來。

以上就是 RecyclerView 刷新列表的源碼分析了,使用了觀察者設(shè)計模式,對此,我們也可以使用該模式去處理一些有觀察和被觀察關(guān)系的場景。

3. 以公眾號推送為例介紹觀察者設(shè)計模式的精簡用法

觀察者:觀察者需要被 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 和 小明同學(xué)
        WXUser vegen = new WXUser("vegen");
        WXUser xiaoming = new WXUser("小明同學(xué)");

        // 微信公眾號 - 用戶訂閱公眾號
        WXxxxObservable.register(vegen);
        WXxxxObservable.register(xiaoming);

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

        // 微信公眾號 - 用戶取消訂閱公眾號
        WXxxxObservable.unregister(vegen);

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

}

vegen 和 小明同學(xué) 都能收到 文章巴拉巴拉1 的提示,vegen 后面取消了訂閱,就只有 小明同學(xué)收到了 文章巴拉巴拉2 的提示。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容