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 }
View Code
 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 }
View Code

这里就是遍历所有观察者,并调用它们的 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 }
View Code

从程序中可以看到,在设置 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 }
View Code

他又继承自 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 }
View Code
 

当 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 绘制三大流程。
 

总结

  • 观察者和被观察者之间是抽象解耦,应对业务变化
  • 增强系统灵活性,可扩展性


猜你喜欢

转载自www.cnblogs.com/Tencen/p/9832412.html