ListView源码解析(二) Adapter

来源:互联网 发布:易语言人工智能机器人 编辑:程序博客网 时间:2024/05/31 06:23

ListView源码解析(二) Adapter

1 说明

在开始解析源码之前,至少要了解观察者模式,不懂的可以去百度一下,稍微了解一下就好.

其实 Adapter相当于是主题类,ListView相当于是订阅者,先明白这个,可能就容易理解很多

2 源码分析

首先咱们从 setAdapter方法开始分析

  • ListView
  /**     * Sets the data behind this ListView.     *     * The adapter passed to this method may be wrapped by a {@link WrapperListAdapter},     * depending on the ListView features currently in use. For instance, adding     * headers and/or footers will cause the adapter to be wrapped.     *     * @param adapter The ListAdapter which is responsible for maintaining the     *        data backing this list and for producing a view to represent an     *        item in that data set.     *     * @see #getAdapter()      */    @Override    public void setAdapter(ListAdapter adapter) {        //注释1        if (mAdapter != null && mDataSetObserver != null) {            mAdapter.unregisterDataSetObserver(mDataSetObserver);        }        //清空ListView        resetList();        //清空View缓存        mRecycler.clear();        //处理头尾布局        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {            mAdapter = wrapHeaderListAdapterInternal(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();            //注释2            //注册订阅者            mDataSetObserver = new AdapterDataSetObserver();            mAdapter.registerDataSetObserver(mDataSetObserver);            //给RecycleBin设置 ViewType            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();    }

从上面可以看出,设置adapter,其实就是给mAdapter赋值,然后调用requestLayout()进行重新布局,上篇我们讲了ListView的绘制流程,那么这里就不多说

从注释1 我们可以看到,如果有adapter,那么就将mDataSetObserver移出注册,在注释2处,又重新注册了一个AdapterDataSetObserver类型的对象,那么这个对象是什么呢,我们跟进去看

它其实是AbsListView的一个内部类

 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {        @Override        public void onChanged() {            super.onChanged();            //快速滑动            if (mFastScroll != null) {                mFastScroll.onSectionsChanged();            }        }        @Override        public void onInvalidated() {            super.onInvalidated();            //快速滑动            if (mFastScroll != null) {                mFastScroll.onSectionsChanged();            }        }    }

里面有两个方法,一个changed,一个重绘,其实调用的都是super的方法,我们跟进

这个类又是AdapterView的内部类

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();        }        @Override        public void onInvalidated() {            mDataChanged = true;            if (AdapterView.this.getAdapter().hasStableIds()) {                // Remember the current state for the case where our hosting activity is being                // stopped and later restarted                mInstanceState = AdapterView.this.onSaveInstanceState();            }            // Data is invalid so we should reset our state            mOldItemCount = mItemCount;            mItemCount = 0;            mSelectedPosition = INVALID_POSITION;            mSelectedRowId = INVALID_ROW_ID;            mNextSelectedPosition = INVALID_POSITION;            mNextSelectedRowId = INVALID_ROW_ID;            mNeedSync = false;            checkFocus();            requestLayout();        }        public void clearSavedState() {            mInstanceState = null;        }    }

上面的两个方法,onInvalidated/onChanged最后都调用了 requestLayout()方法,
那这两个方法有什么区别呢,他还有个父类,我们继续跟进,主要是看注释

/** * Receives call backs when a data set has been changed, or made invalid. The typically data sets * that are observed are {@link Cursor}s or {@link android.widget.Adapter}s. * DataSetObserver must be implemented by objects which are added to a DataSetObservable. * 当数据变化或无效的时候会被调用,标准的一个订阅者,最后又说必须添加到DataSetObservable,这个就是主题类,这里就看可以看出,这是一个观察者 */public abstract class DataSetObserver {    /**     * This method is called when the entire data set has changed,     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.     * 当数据变化的时候调用     */    public void onChanged() {        // Do nothing    }    /**     * This method is called when the entire data becomes invalid,     * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a     * {@link Cursor}.     * 数据全部无效的时候调用     */    public void onInvalidated() {        // Do nothing    }}

从上面,我们可以大胆的猜测,adapter中维护了一个订阅者队列,当调用notifyDateSetChange的时候,会回调订阅者里面的方法.
我们再回到 setAdater方法中,进入adapter.registerDataSetObserver方法,看看是不是正如我们所想的那样,我们先看一个类图

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);    }    /**     * Notifies the attached observers that the underlying data has been changed     * and any View reflecting the data set should refresh itself.     * 数据有变化时调用     */    public void notifyDataSetChanged() {        mDataSetObservable.notifyChanged();    }    /**     * Notifies the attached observers that the underlying data is no longer valid     * or available. Once invoked this adapter is no longer valid and should     * not report further data set changes.     * 数据不再有效时调用     */    public void notifyDataSetInvalidated() {        mDataSetObservable.notifyInvalidated();    }    public boolean areAllItemsEnabled() {        return true;    }    public boolean isEnabled(int position) {        return true;    }    public View getDropDownView(int position, View convertView, ViewGroup parent) {        return getView(position, convertView, parent);    }    public int getItemViewType(int position) {        return 0;    }    public int getViewTypeCount() {        return 1;    }    public boolean isEmpty() {        return getCount() == 0;    }}

如果了解观察者模式的话,到这里基本逻辑就已近很清晰了,注册移除和notifyDateSetchanged都是通过DataSetObservable完成的

我们看一下这个对象和他的父类

public class DataSetObservable extends Observable<DataSetObserver> {    public void notifyChanged() {        synchronized(mObservers) {            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onChanged();            }        }    }    public void notifyInvalidated() {        synchronized (mObservers) {            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onInvalidated();            }        }    }}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);        }    }    public void unregisterAll() {        synchronized(mObservers) {            mObservers.clear();        }    }}

我删除了一些注释,这里,其实注册订阅者,就是将他们放到一个集合中,当我们需要notify的时候,逐个调用他们的方法(onChanged/onInvalidated),移除注册就是从列表中移除注册的对象

到这里,我们的分析就结束了,下面总结一下

3 总结

Adapter内部维护了一个DataSetObservable对象,这是一个主题类,内部有一些订阅者,在给ListView.setAdapter的时候,会注册一个订阅者进去,我们调用adapter.notifyDataSetChanged的时候,会调用DataSetObservable.notifyChanged()方法,这个方法会逐个遍历DataSetObservable内部的订阅者对象,然后调用他们的onChanged方法,在onChanged方法调用 requestLayout();进行ListView的数据重新填充.

在这里主题类由BaseAdapter.mDataSetObservable担当,订阅者由AbsListView的内部类AdapterDataSetObserver担当

原创粉丝点击