Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 《Android源碼設計模式解析與實戰》讀書筆記(十二)

《Android源碼設計模式解析與實戰》讀書筆記(十二)

編輯:關於Android編程

第十二章、觀察者模式

觀察者模式是一個使用率非常高的模式,它最常用在GUI系統、訂閱–發布系統。因為這個模式的一個重要作用就是解耦,將被觀察者和觀察者解耦,使得它們之間的依賴性更小,甚至做到毫無依賴。比如安卓的開源項目EventBus、Otto、AndroidEventBus等事件總線類的和RxJava響應式編程其核心都是使用觀察者模式。

1.定義

觀察者模式是一種行為類模式,它定義對象間一種一對多的依賴關系,使得每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新。

2.使用場景

(1)關聯行為場景,需要注意的是,關聯行為是可拆分的,而不是“組合”關系。

(2)事件多級觸發場景。

(3)跨系統的消息交換場景,如消息隊列、事件總線的處理機制。

3.簡單實現

這裡舉一個追劇的例子,平常為了不錯過最新的電視劇我們會訂閱或關注這個電視劇,當電視劇更新後會第一時間推送給我們,下來就簡單實現一下。

抽象觀察者類

/**
 *  抽象觀察者類,為所有具體觀察者定義一個接口,在得到通知時更新自己
 */
public interface Observer {
    /**
     *  有更新
     *  
     *  @param message 消息
     */
    public void update(String message);

}

抽象被觀察者類

/**
 * 抽象被觀察者類
 */
public interface Observable {

    /**
     * 推送消息
     * 
     * @param message 內容
     */
    void push(String message);

    /**
     * 訂閱
     * 
     * @param observer 訂閱者
     */
    void register(Observer observer);
}

具體的觀察者類

/**
 * 具體的觀察者類,也就是訂閱者
 */
public class User implements Observer {

    @Override
    public void update(String message) {
        System.out.println(name + "," + message + "更新了!");

    }

    // 訂閱者的名字
    private String name;

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

具體的被觀察者類

/**
 *  具體的被觀察者類,也就是訂閱的節目
 */
public class Teleplay implements Observable{

    private List list = new ArrayList();//儲存訂閱者

    @Override
    public void push(String message) {
        for(Observer observer:list){
            observer.update(message);
        }
    }

    @Override
    public void register(Observer observer) {
        list.add(observer);
    }

}

實現

public class Client {
    public static void main(String[] args) {
        //被觀察者,這裡就是用戶訂閱的電視劇
        Teleplay teleplay = new Teleplay();
        //觀察者,這裡就是訂閱用戶
        User user1 = new User("小明");
        User user2 = new User("小光");
        User user3 = new User("小蘭");
        //訂閱
        teleplay.register(user1);
        teleplay.register(user2);
        teleplay.register(user3);
        //推送新消息
        teleplay.push("xxx電視劇");
    }
}

結果

小明,xxx電視劇更新了!
小光,xxx電視劇更新了!
小蘭,xxx電視劇更新了!

由上面的代碼可以看出實現了一對多的消息推送,推送消息都是依賴Observer和Observable這些抽象類,而User和Teleplay完全沒有耦合,保證了訂閱系統的靈活性和可擴展性。

4.Android源碼中的觀察者模式

1.BaseAdapter

BaseAdapter我相信大家都不陌生,在ListView的適配器中我們都是繼承它。下面來簡單分析分析。

BaseAdapter 部分代碼:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {

    //數據集觀察者
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public boolean hasStableIds() {
        return false;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    /**
     * 當數據集變化時,通知所有觀察者
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

看看mDataSetObservable.notifyChanged()方法:

public class DataSetObservable extends Observable {
    /**
     * Invokes {@link DataSetObserver#onChanged} on each observer.
     * Called when the contents of the data set have changed.  The recipient
     * will obtain the new contents the next time it queries the data set.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            // 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();
            }
        }
    }

可以看出在mDataSetObservable.notifyChanged()中遍歷所有觀察者,並調用他們的onChanged(),從而告知觀察者發生了什麼。

那麼觀察者怎麼來的,那就是setAdapter方法,代碼如下:

 @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);//注冊觀察者

            ......省略
        }

AdapterDataSetObserver定義在ListView的父類AbsListView中,是一個數據集觀察者,代碼:

class AdapterDataSetObserver extends AdapterView.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }
    }

它由繼承自AbsListView的父類AdapterView的AdapterDataSetObserver, 代碼如下 :

class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;
        // 上文有說道,調用Adapter的notifyDataSetChanged的時候會調用所有觀察者的onChanged方法,核心實現就在這裡
        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            // 獲取Adapter中數據的數量
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            // 重新布局ListView、GridView等AdapterView組件
            requestLayout();
        }

        // 代碼省略

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

當ListView的數據發生變化時,調用Adapter的notifyDataSetChanged函數,這個函數又會調用DataSetObservable的notifyChanged函數,這個函數會調用所有觀察者 (AdapterDataSetObserver) 的onChanged方法。這就是一個觀察者模式!

5.總結

1.優點

(1)觀察者和被觀察者之間是抽象耦合,應對業務變化。

(2)增強系統的靈活性和可擴展性。

2.缺點

在應用觀察者模式時需要考慮一下開發效率和運行效率的問題,程序中包括一個被觀察者、多個觀察者,開發、調試等內容會比較復雜,而且在Java中消息的通知一般是順序執行,那麼一個觀察者卡頓,會影響整體的執行效率,在這種情況下,一般會采用異步實現。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved