版权声明:本文为博主原创文章,转载请注明原帖地址,谢谢 https://blog.csdn.net/AooMiao/article/details/67632856
前言:在我们使用listview的时候,例如使用网络请求返回一个数据显示在listview上,对listview里的子控件赋值后,我们都会调用adapter.notifyDataSetChanged()方法来刷新listview,界面就显示了那个数据,其中的原理是通过观察者模式来实现的。这里以BaseAdapter为例
BaseAdapter源码:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
............
}
说明:BaseAdapter 里面定义了一个具体被观察者mDataSetObservable ,还有四个方法(注重前三个):注册观察者,删除观察者,通知观察者干活
listview.setAdapter源码:
public class ListView extends AbsListView {
.................
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
............
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;//!!!
}
super.setAdapter(adapter);
if (mAdapter != null) {
............
mDataSetObserver = new AdapterDataSetObserver();//!!!
mAdapter.registerDataSetObserver(mDataSetObserver);//!!!
............
}
}
.................
}
说明:刚开始会先判断是否已经有别的adapter和listview绑定了,有就注销之前的具体观察者(免得待会要通知它)
注意看我标注的//!!!那三行代码:
- 把adapter参数赋给成员变量mAdapter;
- 定义一个AdapterDataSetObserver对象
调用mAdapter(实际上这里是BaseAdapter对象)注册方法注册AdapterDataSetObserver对象(干活那个)
不难理解AdapterDataSetObserver肯定是继承了抽象观察者类的下面看AdapterDataSetObserver源码:
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();
}
}
}
调用onChanged方法里面会调用父类super.onChanged()方法,如下:
class AdapterDataSetObserver extends DataSetObserver {
private Parcelable mInstanceState = null;
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout();
}
说明:是不是很清楚了,它继承了抽象观察者类,重写onChanged()方法,里面逻辑就是把listview的界面重新布局,让数据重新显示。
总结:
- BaseAdapter里面有一个具体被观察者
- listview.setAdapter(BaseAdapter对象)里面生成一个具体观察者,调用BaseAdapter对象注册具体观察者
- 调用adapter.notifyDataSetChanged()方法后,adapter就是BaseAdapter对象,所以会调用BaseAdapter里面的具体被观察者mDataSetObservable的notifyChanged()方法(通知列表的所有观察者干活)
- 调用AdapterDataSetObserver的onChanged()方法,显示数据
观察者模式让数据和界面都依赖于借口,实现了解耦,方便扩展工作。