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方法,看看是不是正如我们所想的那样,我们先看一个类图
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担当
- ListView源码解析(二) Adapter
- 王学岗ListView和源码解析(二)
- ListView(二)通用的Adapter
- base-adapter-helper源码解析
- android源码解析--ListView
- android源码解析--ListView
- ListView源码解析
- android listview源码解析
- listview源码解析
- Listview源码解析(一)
- ListView 源码解析
- ListView 源码解析
- ListView[2] 源码解析
- ListView源码解析
- Day7、ListView和适配器Adapter二
- ListView解析二
- ListView Adapter
- Adapter ListView
- 代码分页
- 告诉各位为如何学习linux系统
- FastDFS分布式文件系统的安装(集群)
- jeecg 数据字典的定义和使用
- HDU 6186 CS Course
- ListView源码解析(二) Adapter
- jmeter正则表达式提取器使用实例
- 面试
- Delphi 快速初始化功能树(cxTreeView)
- Android 文字绘制(DrawText)技术总结
- 哈希表入门--详解
- live555 源码分析:MediaSever
- ubuntu安装显卡驱动+cuda+cudnn+vsftp
- 静态内部类单例缓存地区