Android框架设计模式(三)——Observer Method

来源:互联网 发布:交换机压力测试软件 编辑:程序博客网 时间:2024/06/03 06:26

  • 一观察者模式
    • 什么是控制反转和依赖倒置
      • 依赖倒置
      • 控制反转
    • 什么是观察者模式
      • 定义
      • UML图
      • 适用场景
  • 二观察者模式在Android框架中的应用
    • BaseAdapter适配器
    • 其他应用

一、观察者模式


在介绍观察者模式之前,先补充两个概念:IOC(控制反转)、DIP(依赖倒置)。

什么是控制反转和依赖倒置?


依赖倒置(控制反转),是框架设计的核心,因为有了它们会产生框架,框架的核心就是把【不变】的留在框架层次,把【变化】的留在应用层次,然后两个层次之间通过接口来实现沟通,降低耦合。它们两者本质是同样的,只是一个是从原则上面描述,一个是从方式上面描述。

依赖倒置:

  • 高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。
  • 抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。

控制反转:

高层框架不应该依赖于底层的实现,底层的实现应该依赖于高层的框架,高层框架封装不变的部分,把变化的部分留出接口让底层实现,通过接口来实现高层与底层之间的沟通。在这个沟通的过程中,框架是主动的(即调用者),而底层的具体应用实现是被动的(被调用者)。

总体来说,依赖倒置与控制反转都是一个意思:依赖于接口编程,将具体的对象之间的关系通过轻量型的接口来分离,框架层通过接口调用应用层的不同实现(此处即框架与应用层解耦),达到反向控制的目的。依赖倒置是原则,控制反转是体现。

一般来说,IOC有两种实现的方式:
(1)继承( Inheritance)+卡隼函数(hook)——在 Template Pattern中使用
(2)委托( Delegation)+卡隼函数(hook)——在Observer模式中使用


什么是观察者模式?


定义:

百度百科:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件(通知者)管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

通俗举例:
通俗来说,举古代打仗为例,敌军为数据集合(被观察者),军官为视图(观察者)。那么中间的通知者就是侦察兵,侦察兵在前线侦查敌情的变动,一有风吹草动就会通知军官,然后军官采取相应的方案。这里军官就是观察者,侦察兵就是通知者(不同角度可能角色会转换)。


UML图

这里写图片描述


适用场景

当一个对象的改变需要通知其它对象的时候,同时他又不知道具体有多   需要相互依赖的实体对象解耦,让他们共同依赖于抽象接口(类别),这样即使两个具体对象有改动(只要接口没有变),也不会影响到对方。而且观察者模式可以实现一个通知者,通知多个完全不同的观察者。

二、观察者模式在Android框架中的应用


BaseAdapter适配器

Adapter(适配器),单独本身就是一种模式。但是在Android中,它还有另一个身份————观察者模式中的通知者。

Android里面实现观察者模式是基于组合,而不是继承的。即,观察者和通知者都是镶嵌在ListView和Adapter中,这样的好处是降低了宿主ListView、Adapter与Observer和Observerable的耦合性。

Android里面ListView的观察者模式的开始是下面经典代码:

   MyAdapter adapter = new MyAdapter();   listView.setAdapter(adapter);

我们来看看setAdapter中做了什么事:

 @Override    public void setAdapter(ListAdapter adapter) {        //解除之前的Observer        if (mAdapter != null && mDataSetObserver != null) {            mAdapter.unregisterDataSetObserver(mDataSetObserver);        }        //清除之前的缓存,重新更新视图集合        resetList();        mRecycler.clear();        //获取通知者引用(Adapter)        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);        } else {            mAdapter = adapter;        }        mOldSelectedPosition = INVALID_POSITION;        mOldSelectedRowId = INVALID_ROW_ID;        // AbsListView#setAdapter will update choice mode states.        super.setAdapter(adapter);        //在通知者方注册观察者,以便数据集改变的时候发出通知        if (mAdapter != null) {            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();            mOldItemCount = mItemCount;            mItemCount = mAdapter.getCount();            checkFocus();            mDataSetObserver = new AdapterDataSetObserver();         //注册观察者            mAdapter.registerDataSetObserver(mDataSetObserver);            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());            int position;            if (mStackFromBottom) {                position = lookForSelectablePosition(mItemCount - 1, false);            } else {                position = lookForSelectablePosition(0, true);            }            setSelectedPositionInt(position);            setNextSelectedPositionInt(position);            if (mItemCount == 0) {                // Nothing selected                checkSelectionChanged();            }        } else {            mAreAllItemsSelectable = true;            checkFocus();            // Nothing selected            checkSelectionChanged();        }        requestLayout();    }

看了setAdapter源码,里面有两个地方是观察者模式使用的核心:
即:

//获取通知者引用(Adapter)        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);        } else {            mAdapter = adapter;        } mDataSetObserver = new AdapterDataSetObserver();//调用通知者的方法注册观察者            mAdapter.registerDataSetObserver(mDataSetObserver);

ListView获取Adapter的通知者引用,然后通过Adapter.registerDataSetObserver(),让通知者Adapter获得ListView的观察者接口,这样就实现了双向沟通的通道,绑定完成。

我们再来看通知者BaseAdapter的源码

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {    private final DataSetObservable mDataSetObservable = new DataSetObservable();//通知者引用    public boolean hasStableIds() {        return false;    }    //注册观察者绑定    public void registerDataSetObserver(DataSetObserver observer) {        mDataSetObservable.registerObserver(observer);    }    //解除观察者绑定    public void unregisterDataSetObserver(DataSetObserver observer) {        mDataSetObservable.unregisterObserver(observer);    }    /**     * 通知已注册的观察者,数据集已经改变。任何观察者在收到该信息         * 之后必须更新自己。     */    public void notifyDataSetChanged() {        mDataSetObservable.notifyChanged();    }    /**     * Notifies the attached observers that the underlying data is no longer valid     * or available. Once invoked this adapter is no longer valid and should     * not report further data set changes.     */    public void notifyDataSetInvalidated() {        mDataSetObservable.notifyInvalidated();    }    public boolean areAllItemsEnabled() {        return true;    }    public boolean isEnabled(int position) {        return true;    }    public View getDropDownView(int position, View convertView, ViewGroup parent) {        return getView(position, convertView, parent);    }    public int getItemViewType(int position) {        return 0;    }    public int getViewTypeCount() {        return 1;    }    public boolean isEmpty() {        return getCount() == 0;    }}

从上面的源码我们可以看到,BaseAdapter里面有一个Observerable通知者对象。在ListView调用了setAdapter()方法后,就实现了通知者与观察者的绑定,当Adapter里面的数据集合改变时,容器Activity通过调用Adapter.notifyDataSetChanged()然后再通过Observerable.notifyChanged方法通知ListView数据集改变了,然后就会调用ListView中DataObserver的onChaned()方法更新界面。
我们来看看真正的Observer和Observerable接口的源码。

  • ListView中的AdapterDataSetObserver源码:
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();            }        }    }
  • Adapter中的DataSetObserverable源码:
public class DataSetObservable extends Observable<DataSetObserver> {    /**     * 通知观察者数据集改变了     */    public void notifyChanged() {        synchronized(mObservers) {            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onChanged();            }        }    }    public void notifyInvalidated() {        synchronized (mObservers) {            for (int i = mObservers.size() - 1; i >= 0; i--) {                mObservers.get(i).onInvalidated();            }        }    }}

由于Android框架系统比较复杂,因此它并没有采取Gof的实现接口的方式来实现观察者模式,而是通过委托的方式(嵌套一个通知者、观察者),委托通知者和观察者来实现通知和接收通知的任务。


其他应用

观察者模式在Android中的应用还有很多。
比如:

  • 广播机制中的BroadCast(通知者)和BroadReceiver(观察者);

  • Service中的Service(通知者)和ServiceConnection(观察者),当服务启动成功后,就调用onBind()方法通知ServiceConnection服务已经启动,通过 onServiceConnected()将Binder返回给观察者;

1 0