Android项目中观察者模式解析
ListView 是 Android 中重要的控件之一,而 ListView 最重要的一个功能就是 Adapter,BaseAdapter 就是一个观察者模式。具体代码如下:
1 public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { 2 private final DataSetObservable mDataSetObservable = new DataSetObservable(); 3 4 public boolean hasStableIds() { 5 return false; 6 } 7 8 public void registerDataSetObserver(DataSetObserver observer) { 9 mDataSetObservable.registerObserver(observer); 10 } 11 12 public void unregisterDataSetObserver(DataSetObserver observer) { 13 mDataSetObservable.unregisterObserver(observer); 14 } 15 16 /** 17 * Notifies the attached observers that the underlying data has been changed 18 * and any View reflecting the data set should refresh itself. 19 */ 20 public void notifyDataSetChanged() { 21 mDataSetObservable.notifyChanged(); 22 } 23 24 /** 25 * Notifies the attached observers that the underlying data is no longer valid 26 * or available. Once invoked this adapter is no longer valid and should 27 * not report further data set changes. 28 */ 29 public void notifyDataSetInvalidated() { 30 mDataSetObservable.notifyInvalidated(); 31 } 32 33 public boolean areAllItemsEnabled() { 34 return true; 35 } 36 37 public boolean isEnabled(int position) { 38 return true; 39 } 40 41 public View getDropDownView(int position, View convertView, ViewGroup parent) { 42 return getView(position, convertView, parent); 43 } 44 45 public int getItemViewType(int position) { 46 return 0; 47 } 48 49 public int getViewTypeCount() { 50 return 1; 51 } 52 53 public boolean isEmpty() { 54 return getCount() == 0; 55 } 56 }
1 public class DataSetObservable extends Observable<DataSetObserver> { 2 //调用每个函数的 onChanged() 方法通知他们的被观察者发生变化 3 public void notifyChanged() { 4 synchronized(mObservers) { 5 for (int i = mObservers.size() - 1; i >= 0; i--) { 6 mObservers.get(i).onChanged(); 7 } 8 } 9 } 10 }
这里就是遍历所有观察者,并调用它们的 onChanged() 方法,从而告知观察者发生了变化。
观察者就是 ListView 通过 setAdapter 时产生的,相关代码:
1 @Override 2 public void setAdapter(ListAdapter adapter) { 3 //如果已经有了一个Adapter,先注销该Adapter对应的观察者 4 if (null != mAdapter) { 5 mAdapter.unregisterDataSetObserver(mDataSetObserver); 6 } 7 8 resetList(); 9 mRecycler.clear(); 10 11 if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { 12 mAdapter = new PLA_HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); 13 } else { 14 mAdapter = adapter; 15 } 16 17 mOldSelectedPosition = INVALID_POSITION; 18 mOldSelectedRowId = INVALID_ROW_ID; 19 if (mAdapter != null) { 20 mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); 21 mOldItemCount = mItemCount; 22 mItemCount = mAdapter.getCount(); 23 checkFocus(); 24 //创建一个数据集观察者 25 mDataSetObserver = new AdapterDataSetObserver(); 26 //将这个观察者注册到Adapter中,实际是注册到 DataSetObservable 中 27 mAdapter.registerDataSetObserver(mDataSetObserver); 28 29 mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); 30 } else { 31 mAreAllItemsSelectable = true; 32 checkFocus(); 33 // Nothing selected 34 } 35 36 requestLayout(); 37 }
从程序中可以看到,在设置 Adapter 时会构建一个 AdapterDataSetObserver,这就是上面所说的观察者,最后,将这个观察者注册到 Adapter 中,这样被观察者、观察者都有了。
AdapterDataSetObserver 定义在 ListView 的父类 AbsListView 中,具体代码如下:
1 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { 2 @Override 3 public void onChanged() { 4 super.onChanged(); 5 if (mFastScroll != null) { 6 mFastScroll.onSectionsChanged(); 7 } 8 } 9 10 @Override 11 public void onInvalidated() { 12 super.onInvalidated(); 13 if (mFastScroll != null) { 14 mFastScroll.onSectionsChanged(); 15 } 16 } 17 }
他又继承自 AbsListView 的父类 AdapterView<ListAdapter>.AdapterDataSetObserver,具体代码如下:
1 class AdapterDataSetObserver extends DataSetObserver { 2 private Parcelable mInstanceState = null; 3 4 //上文讲过,调用Adapter的notifyDataSetChanged会调用所有观察者的onChanged方法,核心实现就在这里 5 @Override 6 public void onChanged() { 7 mDataChanged = true; 8 mOldItemCount = mItemCount; 9 mItemCount = getAdapter().getCount(); 10 if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null 11 && mOldItemCount == 0 && mItemCount > 0) { 12 AdapterView.this.onRestoreInstanceState(mInstanceState); 13 mInstanceState = null; 14 } else { 15 rememberSyncState(); 16 } 17 checkFocus(); 18 //重新布局ListView,GridView等AdapterView组件 19 requestLayout(); 20 } 21 22 @Override 23 public void onInvalidated() { 24 mDataChanged = true; 25 26 if (AdapterView.this.getAdapter().hasStableIds()) { 27 mInstanceState = AdapterView.this.onSaveInstanceState(); 28 } 29 30 mOldItemCount = mItemCount; 31 mItemCount = 0; 32 mSelectedPosition = INVALID_POSITION; 33 mSelectedRowId = INVALID_ROW_ID; 34 mNextSelectedPosition = INVALID_POSITION; 35 mNextSelectedRowId = INVALID_ROW_ID; 36 mNeedSync = false; 37 38 checkFocus(); 39 requestLayout(); 40 } 41 42 public void clearSavedState() { 43 mInstanceState = null; 44 } 45 }
当 ListView 的数据发生变化时,调用 Adapter 的 notifyDataSetChanged 会调用所有观察者的onChanged 方法,在 onChanged 方法中又会调用 ListView 的 requestLayout 进行重新布局使得 ListView 刷新界面。
最后,再整理一下这个过程,AdapterListView 中有一个内部类 AdapterDataSetObserver,在 ListView 中设置 Adapter 时会创建 AdapterDataSetObserver,并且注册到 Adapter 中,这就是一个观察者,而 Adapter 中包含一个数据集可观察者 DataSetObservable,在数据数量发送变更时,开发者手动调用 Adapter.notifyDataSetChanged,而 notifyDataSetChanged 实际上会调用 DataSetObservable 的 notifyChanged 函数,该函数会遍历所有观察者的 onChanged 方法,在 AdapterDataSetObserver 的 onChanged 中会获取 Adapter 中数据集的新数量,然后调用 requestLayout 进行 View 绘制三大流程。
总结
- 观察者和被观察者之间是抽象解耦,应对业务变化
- 增强系统灵活性,可扩展性