首页 > 代码库 > 【安卓笔记】数据适配器(adapter)中的观察者模式
【安卓笔记】数据适配器(adapter)中的观察者模式
ListView要想显示数据,需要用到数据适配器即Adapter。而当我们删除ListView的某个条目时,数据适配器中的数据源必然发生改变,这时候我们通过调用适配器类提供的notifyDataSetChanged方法通知listview数据发生改变,请求重新绘制。
这其中其实使用了一种比较常见的设计模式,即观察者模式。
在分析数据适配器中涉及到的观察者模式之前,我们先简单了解下什么是观察者模式。
观察者模式的定义:定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
上面是观察者模式的类图。Subject类中通过Attach/Detach方法去绑定/解绑一个或者多个观察者(Observer)对象,当Subject出现某种Observer感兴趣的事件时,Subject将会调用notify方法通知所有绑定的Observer对象,调用其update方法更新数据。
下面我们试着分析数据适配器中的观察者模式。
这里我们可以从BaseAdapter的notifyDataSetChanged开始跟踪源码。
定位到该方法,我们发现只有一行代码,即调用了mDataSetObservable对象的notifyChanged方法。
public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); }这个mDataSetObservable即被观察的对象,它是一个DataSetObservable类型。我们来看下其实现:
package android.database; public class DataSetObservable extends Observable<DataSetObserver> { public void notifyChanged() { synchronized(mObservers) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } }
可以看到,在它的notifyChanged方法中调用了每一个观察者的onChanged回调方法,这个mObservers即观察者集合,它的定义在DataSetObservable的父类Observable中,另外,这里通过泛型指定了观察者类型必须为DataSetObserver类型。
我们打开Observable源码:
package android.database; import java.util.ArrayList; 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); } } ... }
这个类定义了一个ArrayList类型的观察者集合,并且提供了两个方法用来注册/解除注册 一个观察者,其实就是调用集合的remove/add方法。
到这里我们明白了调用适配器的notifyDataSetChanged方法最终会通知所有已经注册过的观察者们,调用每个观察者的onChanged方法。
如果ListView在删除一个条目后,想要更新界面,必然在此之前注册了一个观察者,并且该观察者的onChanged方法中必然会有界面重绘的代码。而ListView跟适配器打交道的方式是setAdapter方法,可想而知,此方法中肯定有注册观察者的代码。
根据这个思路,我们定位到ListView的setAdapter方法:
public void setAdapter(ListAdapter adapter) { ... ... super.setAdapter(adapter); if (mAdapter != null) { ... ... mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); ... ... } else { ... ... } requestLayout(); }果然,在这个方法中我们找到了注册观察者的代码,但是这里的观察者是AdapterDataSetObserver类型的,而Adapter要求的是DataSetObserver类型的,那么很显然,AdapterDataSetObserver是DataSetObserver的子类。该类的定义在ListView的父类AbsListView中:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } ... ... }而AbsListView中的AdapterDataSetObserver又继承了AdapterView类中的AdapterDataSetObserver。最终,我们再AdapterView中找到AdapterDataSetObserver:
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(); } ... ... }
可以看到,这个类的确继承了DataSetObserver,并且在onChanged中调用了requestLayout去刷新布局。到这里我们明白了整个流程,另外也看到了观察者模式在实际项目中的使用,确实很强大。
最后附上一张图,方便大家理解。
【安卓笔记】数据适配器(adapter)中的观察者模式
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。