【安卓笔记】数据适配器(adapter)中的观察者模式

来源:互联网 发布:centos 7 ip配置 nat 编辑:程序博客网 时间:2024/06/02 05:29
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去刷新布局。到这里我们明白了整个流程,另外也看到了观察者模式在实际项目中的使用,确实很强大。
最后附上一张图,方便大家理解。











1 0
原创粉丝点击