【安卓筆記】資料配接器(adapter)中的觀察者模式

來源:互聯網
上載者:User

標籤:

ListView要想顯示資料,需要用到資料配接器即Adapter。而當我們刪除ListView的某個條目時,資料配接器中的資料來源必然發生改變,這時候我們通過調用適配器類提供的notifyDataSetChanged方法通知listview資料發生改變,請求重新繪製。這其中其實使用了一種比較常見的設計模式,即觀察者模式。
在分析資料適配器中涉及到的觀察者模式之前,我們先簡單瞭解下什麼是觀察者模式。 觀察者模式的定義:定義對象間的一種一對多的依賴關係,使得每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新。
上面是觀察者模式的類圖。Subject類中通過Attach/Detach方法去綁定/解除綁定一個或者多個觀察者(Observer)對象,當Subject出現某種Observer感興趣的事件時,Subject將會調用notify方法通知所有綁定的Observer對象,調用其update方法更新資料。
下面我們試著分析資料適配器中的觀察者模式。這裡我們可以從BaseAdapter的notifyDataSetChanged開始跟蹤源碼。定位到該方法,我們發現只有一行代碼,即調用了mDataSetObservable對象的notifyChanged方法。
 public void notifyDataSetChanged() {        mDataSetObservable.notifyChanged();    }
這個mDataSetObservable即被觀察的對象,它是一個DataSetObservable類型。我們來看下其實現:
package android.database;public class DataSetObservable extends Observable<DataSetObserver> {     public void notifyChanged() {        synchronized(mObservers) {            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onChanged();            }        }    }}
可以看到,在它的notifyChanged方法中調用了每一個觀察者的onChanged回調方法,這個mObservers即觀察者集合,它的定義在DataSetObservable的父類Observable中,另外,這裡通過泛型指定了觀察者類型必須為DataSetObserver類型。我們開啟Observable源碼:
package android.database;import java.util.ArrayList;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);        }    }    ...}
這個類定義了一個ArrayList類型的觀察者集合,並且提供了兩個方法用來註冊/解除註冊 一個觀察者,其實就是調用集合的remove/add方法。到這裡我們明白了調用適配器的notifyDataSetChanged方法最終會通知所有已經註冊過的觀察者們,調用每個觀察者的onChanged方法。如果ListView在刪除一個條目後,想要更新介面,必然在此之前註冊了一個觀察者,並且該觀察者的onChanged方法中必然會有介面重繪的代碼。而ListView跟適配器打交道的方式是setAdapter方法,可想而知,此方法中肯定有註冊觀察者的代碼。根據這個思路,我們定位到ListView的setAdapter方法:
 public void setAdapter(ListAdapter adapter) {       ... ...        super.setAdapter(adapter);        if (mAdapter != null) {           ... ...            mDataSetObserver = new AdapterDataSetObserver();            mAdapter.registerDataSetObserver(mDataSetObserver);         ... ...        } else {          ... ...        }        requestLayout();    }
果然,在這個方法中我們找到了註冊觀察者的代碼,但是這裡的觀察者是AdapterDataSetObserver類型的,而Adapter要求的是DataSetObserver類型的,那麼很顯然,AdapterDataSetObserver是DataSetObserver的子類。該類的定義在ListView的父類AbsListView中:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {        @Override        public void onChanged() {            super.onChanged();            if (mFastScroller != null) {                mFastScroller.onSectionsChanged();            }        }   ... ...    }
而AbsListView中的AdapterDataSetObserver又繼承了AdapterView類中的AdapterDataSetObserver。最終,我們再AdapterView中找到AdapterDataSetObserver:
 class AdapterDataSetObserver extends DataSetObserver {        private Parcelable mInstanceState = null;        @Override        public void onChanged() {            mDataChanged = true;            mOldItemCount = mItemCount;            mItemCount = getAdapter().getCount();            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null                    && mOldItemCount == 0 && mItemCount > 0) {                AdapterView.this.onRestoreInstanceState(mInstanceState);                mInstanceState = null;            } else {                rememberSyncState();            }            checkFocus();            requestLayout();        }  ... ...    }
可以看到,這個類的確繼承了DataSetObserver,並且在onChanged中調用了requestLayout去重新整理布局。到這裡我們明白了整個流程,另外也看到了觀察者模式在實際項目中的使用,確實很強大。最後附上一張圖,方便大家理解。










【安卓筆記】資料配接器(adapter)中的觀察者模式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.