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

一、观察者模式


在介绍观察者模式之前,先补充两个概念: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返回给观察者;

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值