深入理解BaseAdapter与ListView

1.   观察者模式与适配器模式

  观察者模式和适配器模式都是JAVA中最重要的设计模式。观察者模式可以将回调作为其实现的一种方式,适配器模式本质上就是一个类实现了某接口,同时继承了某父类,即拥有接口和父类的所有成员,这就是“适配”的含义。

2.   BaseAdapter与ListView

  在使用ListView的过程中,只要为其传入Adapter即可。由于Android中所有Adapter都继承了BaseAdapter,这里主要研究BaseAdapter。追踪源码,绘制UML图,如图1.

深入理解BaseAdapter与ListView_第1张图片

图1,BaseAdapter与ListView的UML类图

 

1)    BaseAdapter管理观察者

  BaseAdapter最终实现的是Adapter接口,该接口即包含了最重要的几个函数:

+registerDataSetObserver(DataSetObserver observer):void//注册监听器对象oberver

+unregisterDataSetObserver(DataSetObserver observer):void//解除observer对象

+getCount():int//Adapter中数据的个数

+getItem(intposition):Object//Adapter中每个position的数据

+getItemId(int position):long

+getView(int position, View convertView, ViewGroupparent):view//每个position返回的view

 

这里注册的监听器对象是DataSetObserver类型,它是一个接口,只有一个方法,即:

+onChanged():void

 

具体到BaseAdapter,它拥有一个DataSetObservable类型的成员变量,这个成员变量内部:

 -mObservers:ArrayList//泛型的list

+unregisterObserver(T observer):void//注册监听器对象oberver

+registerObserver(Tobserver):void/解除observer对象

+notifyChanged():void//通知变更

BaseAdapter(继承至)中有unregisterObserver和registerObserver两个方法,本身有notifyChanged方法,而BaseAdapter的成员变量DataSetObservable也有这三个方法。没错,最终DataSetObserverobserver是注册到BaseAdapter的成员变量DataSetObservable中去的,notifyChanged方法也是调用DataSetObservable的notifyChanged方法。

public abstractclass BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservablemDataSetObservable = new DataSetObservable();
 
    ……//省略无关内容
   
    public void registerDataSetObserver(DataSetObserverobserver) {
       mDataSetObservable.registerObserver(observer);
    }
 
    public voidunregisterDataSetObserver(DataSetObserver observer) {
       mDataSetObservable.unregisterObserver(observer);
    }
   
    /**
     * Notifies the attached observers that theunderlying data has been changed
     * and any View reflecting the data setshould refresh itself.
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
……//省略无关内容
}


BaseAdapter的成员变量DataSetObservable mDataSetObservable又是如何实现注册DataSetObserver observer、解除DataSetObserverobserver、通知DataSetObserver observer呢?这里的注册,即指的是将DataSetObserver observer添加到DataSetObservable中ListmObservers中,解除DataSetObserver observer即从List mObservers删除,通知即遍历ListmObservers并调用每一项的onChanged()方法。

这里看一下DataSetObservable的父类Observable,注册和解除观察者在这里实现。

public abstract class Observable {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected finalArrayList mObservers = new ArrayList();
 
    /**
     * Adds an observer to the list.The observer cannot be null and it must not already
     * be registered.
     * @param observer the observerto register
     * @throwsIllegalArgumentException the observer is null
     * @throws IllegalStateExceptionthe observer is already registered
     */
    public void registerObserver(Tobserver) {
        if (observer == null) {
            throw newIllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if(mObservers.contains(observer)) {
                throw newIllegalStateException("Observer " + observer + " is alreadyregistered.");
            }
           mObservers.add(observer);
        }
    }
 
    /**
     * Removes a previouslyregistered observer. The observer must not be null and it
     * must already have beenregistered.
     * @param observer the observerto unregister
     * @throwsIllegalArgumentException the observer is null
     * @throws IllegalStateExceptionthe observer is not yet registered
     */
    public void unregisterObserver(Tobserver) {
        if (observer == null) {
            throw newIllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index =mObservers.indexOf(observer);
            if (index == -1) {
                throw newIllegalStateException("Observer " + observer + " was notregistered.");
            }
           mObservers.remove(index);
        }
    }
 
    /**
     * Remove all registeredobservers.
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}

再看一下DataSetObservable本身,notifyChanged()通知所有观察者在这里实现。

public class DataSetObservable extends Observable {
    /**
     * Invokes {@linkDataSetObserver#onChanged} on each observer.
     * Called when the contents ofthe data set have changed.  The recipient
     * will obtain the new contentsthe next time it queries the data set.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() isimplemented by the app, it could do anything, including
            // removing itself from{@link mObservers} - and that could cause problems if
            // an iterator is usedon the ArrayList {@link mObservers}.
            // to avoid suchproblems, just march thru the list in the reverse order.
            for (int i =mObservers.size() - 1; i >= 0; i--) {
               mObservers.get(i).onChanged();
            }
        }
    }
 
    /**
     * Invokes {@linkDataSetObserver#onInvalidated} on each observer.
     * Called when the data set isno longer valid and cannot be queried again,
     * such as when the data set hasbeen closed.
     */
    public void notifyInvalidated(){
        synchronized (mObservers) {
            for (int i =mObservers.size() - 1; i >= 0; i--) {
               mObservers.get(i).onInvalidated();
            }
        }
    }
}

    一句话总结BaseAdapter:BaseAdapter将注册、解除注册、通知观察者的事件都委托给了内部的成员变量DataSetObservablemDataSetObservable,而DataSetObservable mDataSetObservable对于观察者的管理是通过链表进行的。

2)    ListView生成观察者

      通过setAdapter(Tadapter)方法将Adapter实例传入AdapterView(ListView的父类)。这里要传入之前Adapter并没注册任何观察者,那观察者在哪里呢?

  首先明确,监听者的任务是什么。Adapter数据改变,观察者应该提示AdapterView(ListView的父类)重新绘制。显然,观察者应该是AdapterView(ListView的父类)的内部类,它的onChange()函数用于根据Adapter的数据重新绘制AdapterView(ListView的父类)。

查看AdapterView(ListView的父类):

public abstract class AdapterView extends ViewGroup {
 
     ……//省略无关内容
 
  class AdapterDataSetObserver extends DataSetObserver {
 
       private Parcelable mInstanceState = null;
 
       @Override
       public void onChanged() {
           mDataChanged = true;
           mOldItemCount = mItemCount;
           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();
           requestLayout();//View中的函数,用于重新绘制View
       }
    ……//省略无关内容
   }

最后,查看一下ListView的setAdapter(Adapter adapter)。这里应该会将ListView的内部类实现的观察者注册到传入的Adapter adapter,并第一次绘制ListView。


public classListView extends AbsListView {
   ……//省略无关内容
   public void setAdapter(ListAdapter adapter){
        if (mAdapter != null &&mDataSetObserver != null) {//内部已经有Adapter,且观察者不为null,则去除观察者
           mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
 
        resetList();//清空List
        mRecycler.clear();//清空缓存的view
 
        if (mHeaderViewInfos.size() > 0||mFooterViewInfos.size() > 0) {//ListView的头尾部分view
            mAdapter = newHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);//封装传入新的adapter
        } else {
            mAdapter = adapter;//直接传入新的adapter
        }
 
        mOldSelectedPosition =INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;
 
        // AbsListView#setAdapter will updatechoice mode states.
        super.setAdapter(adapter);
 
        if (mAdapter != null) {//根据Adapter重新计算相关属性
            mAreAllItemsSelectable =mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();//个数
            checkFocus();
 
            mDataSetObserver = newAdapterDataSetObserver();//生成新的监听者
           mAdapter.registerDataSetObserver(mDataSetObserver);//注册新的监听者
 
           mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
 
            int position;
            if (mStackFromBottom) {
                position =lookForSelectablePosition(mItemCount - 1, false);
            } else {
                position =lookForSelectablePosition(0, true);
            }
            setSelectedPositionInt(position);
            setNextSelectedPositionInt(position);
 
            if (mItemCount == 0) {
                // Nothing selected
                checkSelectionChanged();
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }
 
        requestLayout();//重新绘制
    }
    ……//省略无关内容
}

3.   总结

     ListView中有个内部类AdapterDataSetObserver,其OnChange()方法是通过计算Adapter来重绘ListView的。

     ListView传入Adapter后,将AdapterDataSetObserver注册到Adapter,即添加到Apdater内部的DataSetObservable(链表类型),并第一次绘制ListView。

     当Apapter数据源变化后,通知Adatpter notify即遍历了DataSetObserver的链表,并调用了AdapterDataSetObserver的onChange()函数,即重绘了ListView。

     注意,由于Apdater内部的DataSetObservable是链表类型,所以,可以注册多个监听者,即多个ListView可以绑定同一个Adapter,数据源变化后会通知所有ListView。

    最后,我认为,适配器模式在这里并没有特别体现(参考2,适配器即Adapter继承/某接口,实现某个类),而着重体现了观察者模式。

参考1:【安卓笔记】数据适配器(adapter)中的观察者模式,http://m.blog.csdn.net/blog/RowandJJ/42293681

参考2:Android源码之ListView的适配器模式,http://www.2cto.com/kf/201502/378700.html

 

你可能感兴趣的:(Android开发)