分享解析baseAdapter源代碼

    今天初七,羊年工作的第一天,這裏f給大家拜個晚年。最近在做項目時候,根據需要涉及到了baseAdapter的一些用法,衆所周知,adapter很好的運用了觀察者模式,f看<head first>時候,看了這個模式,demo也敲過,但是對真正的應用沒有源代碼級別的接觸,於是找時間研究了baseAdapter的源碼,跟大家分享一下。

    baseAdapter作爲一個抽象類,實現了listAdapter以及spinnerAdapter接口,它倆又同樣繼承了adapter接口。adapter接口中有一些抽象方法10個

    listAdapter新增加了方法2個

spinnerAdapter新增加了方法1個

而baseAdapter實現了


    乍一看有些亂,我來捋捋

baseAdapter其實間接,直接的實現了三個adapter裏的方法,listAdapter,spinnerAdapter並未實現adapter的方法,而是新增了方法


registerDataSetObserver(DataSetObserver observer);

unregisterDataSetObserver(DataSetObserver observer);

adapter的這兩個方法是用來註冊 註銷觀察者的。

這兩個方法在baseAdapter裏已經實現

int getCount();
 Object getItem(int position);

long getItemId(int position);

 View getView(int position, View convertView, ViewGroup parent);

adapter的這四個方法沒有被實現,所以我們在自定義adapter繼承baseAdapter時候,也就要重寫這四個方法

adapter的boolean hasStableIds();在baseAdapter裏實現,返回值是false

這個方法的意思是表達每個item的id對於數據集的改變是否是穩定不變的,如果返回true,表示每個object的id都一樣,

如果都一樣,我們修改時候,在內存中指向的便是同一塊地址,這不合邏輯,所以在baseAdapter裏返回false,即

每個object都有不一樣的id。

 int getItemViewType(int position);

int getViewTypeCount();

這兩個方法分別表示通過特定item創建的view的類型和對應的編號

 boolean isEmpty();

這個方法表示是否adapter包含數據

listAdapter中兩個抽象方法分別表示,adapter裏的所有item或者指定位置的item是否是enabled,我們遇到相關需求時候,

可以重寫這些方法,實現不同的目的

baseAdapter重寫spinnerAdapter時候,在重寫的方法裏調用了View getView(int position, View convertView, ViewGroup parent);


adapter觀察者模式的體現,就是register這個方法,方法中執行了觀察者對象的註冊

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

BaseAdapter每次新建時候,都會創建一個類似主題的對象

private final DataSetObservable mDataSetObservable = new DataSetObservable();


這裏還會有點亂。。。

DataSetObservable是Observable<DataSetObserver>的實現類,且看registerObserver方法

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);
        }
    }


在Android裏 DataSetObservable,DataSetObserver作爲觀察者模式的主題和觀察者對象,已經被綁定在一起

在baseAdapter的重寫的方法中已經把兩個對象作爲參數傳入。



什麼是adapter呢?按文檔解釋,adapter是adapterview和對應的view的數據集之間的橋樑,其實就是爲了顯示數據在listview等顯示而創造的

adapter對於觀察者模式的運用最明顯的是adapter的notifyDataSetChanged方法,

public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

 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();
            }
        }
    }

看到這以後,f又習慣性地去找onchanged方法,才發現這個方法是個抽象方法,然後就傻了,大家都知道,調用adapter的notifyDataSetChanged

方法後,界面會重新繪製,但是按照目前的邏輯是不會出現畫界面的結果的。。。怎麼解決呢?對對,那就是debug,看代碼是怎麼運行的

在前面其實埋了一個坑,爲何重寫的方法裏有註冊有註銷,但是是怎麼調用的呢?還記得baseAdapter怎麼用嗎?

要新建,然後調用listview 的setAdapter,這個方法,是個及其重要的方法。

這裏對adapter以及觀察者對象做了判斷,剛開始adapter不爲空,觀察者對象爲空,程序不執行註銷的方法,而是往下運行,

下面,執行了觀察者對象的註冊, mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);

所以在調用notifyDataSetChanged方法時,是有一個觀察者對象存在。

debug到此,進入方法一看,是執行這一步,

傳遞的Index是0,應該不會報數組下標越界的錯

然後又繼續執行重寫的方法。執行完後回到

再次進入後執行

然後數據集包括與之關聯的view都會被移入堆內存等待循環回收。

好亂的感腳。。。

都是f自己debug很多次得到的結論,adapter塊的源碼確實複雜。

不知道分析是否有錯誤,目前f嚴重處於初級階段,還請大家多多跟f交流,彼此提高技術水平,f也會抽時間找一些有意義的內容和大家共享!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章