####
adapter中的观察者模式class AbstractSubject(object):
def register(self, listener):
raise NotImplementedError("Must subclass me")
def deregister(self, listener):
raise NotImplementedError("Must subclass me")
def notify_listeners(self, event):
raise NotImplementedError("Must subclass me")
class Listener(object):
def __init__(self, name, subject):
self.name = name
subject.register(self)
def notify(self, event):
print self.name, "received event", event
class Subject(AbstractSubject):
def __init__(self):
self.listeners = []
self.data = None
def getUserAction(self):
self.data = raw_input('Enter something to do:')
return self.data
# Implement abstract Class AbstractSubject
def register(self, listener):
self.listeners.append(listener)
def deregister(self, listener):
self.listeners.remove(listener)
def notify_listeners(self, event):
for listener in self.listeners:
listener.notify(event)
if __name__=="__main__":
# make a subject object to spy on
subject = Subject()
# register two listeners to monitor it.
listenerA = Listener("<listener A>", subject)
listenerB = Listener("<listener B>", subject)
# simulated event
subject.notify_listeners ("<event 1>")
# outputs:
# <listener A> received event <event 1>
# <listener B> received event <event 1>
action = subject.getUserAction()
subject.notify_listeners(action)
#Enter something to do:hello
# outputs:
# <listener A> received event hello
# <listener B> received event hello
在listview中,我们知道,当数据变化时,listview呈现的内容是会更新的。这实际上是用到了adapter中的观察者模式(当然listview中利用了adapter模式,这个以后再讲)。adapter内部有一个可观察者类,listview则作为他的一个观察者,将adapter设置给listview时,listview会被注册到这个观察者对象中。接下来我们就从adapter的源码入手,分析一下。
@override
public void setAdapter(ListAdapter adapter){
resetList();
//清空视图缓存mRecycler
mRecycler.clear();
if (mAdapter!=null) {
mDataSetObserver=new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
}else {
//代码省略
}
requestLayout();
}
从以上程序中我们可以看出,设置adapter时创建了一个AdapterDataSetObserver对象,并注册到adapter中。刚才不是说listview是观察者吗?这会儿怎么成了AdapterDataSetObserver了。我们先放下这个疑问继续往下看。 首先我们看常用的adapter基类BaseAdapter,部分代码如下:
public abstract class BaseAdapter implements ListAdapter,SpinnerAdapter{
private final DataSetObservable mDataSetObservable=new DataSetObservable();
public void registerDataSetObserver(DataSetObserver dataSetObserver){
mDataSetObservable.registerObserver(dataSetObserver);
}
public void notifyDataSetChanged(){
mDataSetObservable.notifyChanged();
}
//代码省略
}
从以上可以看出,注册观察者实际上调用了DataSetObeservable对应的函数。DataSetObeservable拥有一个观察者集合,当可观察者改变时,就会通知观察者做出相应的处理。 当adapter的数据变化时,我们会调用adapter的notifyDataSetChanged函数,该函数又会调用DataSetObeservable对象的notifyChanged()函数通知所有观察者数据发生了变化,使观察者进行相应的操作。代码如下:
public class DataSetObeservable extends Observable<DataSetObeserver>{
public void notifyChanged(){
synchronized (mObservers){
for (int i=mObservers.size()-1;i>=0;i--){
mObservers.get(i).onChanged();//调用观察者的onChanged()函数
}
}
}
}
对listview来说这个观察者就是AdapterDataSetObeserver对象,该类声明在AdapterView中,也是listview的一个父类。AdapterDataSetObeserver代码如下
//AdapterView的内部类AdapterDataSetObeserver中
class AdapterDataSetObeserver extends DataSetObserver{
@Override
public void onChanged() {
mDataChanged=true;
mOldItemCount=mItemCount;
//获取元素个数
mItemCount=getAdapter().getCount();
//代码省略
checkFocus();
//重新布局
requestLayout();
}
//代码省略
}
在AdapterDataSetObeserver的onChanged()函数中会调用viewGroup的requestLayout()进行重新策略,布局,绘制整个listview的item view,执行完之后,整个listview的元素就发生了变化。
现在我们回到之前的额问题,就是listview不是观察者,而AdapterDataSetObeserver才是真正的观察者的问题。在AdapterDataSetObeserver的onChanged()函数中实际调用的是AdapterView中的方法来完成功能,所以AdapterDataSetObeserver只是在外层做了一层封装,真正核心的功能应该是AdapterView。listview就是通过Adapter模式,观察者模式,item view复用机理实现了高效列表显示。 这里对于item view的复用机理介绍一下: 在Adapter中要重写四个函数:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder=null;
if(convertView==null){
viewHolder=new ViewHolder();
convertView=mInflater.inflate(R.layout.medal_item,null);
viewHolder.medal_item_tv= (TextView) convertView.findViewById(R.id.medal_tv_item);
convertView.setTag(viewHolder);
}else{
viewHolder= (ViewHolder) convertView.getTag();
}
viewHolder.medal_item_tv.setText(data.get(position));
return convertView;
}
public final class ViewHolder{
public TextView medal_item_tv;
}
那么还剩下,listview的适配器模式,下一篇文章再讲。以及在android 5.0以后开始提倡用RecyclerView替代listview了,最近项目里正好用到了这个,有时间也会整理出来,以飨读者。