美文网首页Android面试相关
EventBus设计模式剖析(三)观察者模式

EventBus设计模式剖析(三)观察者模式

作者: YongtaoHuang | 来源:发表于2019-07-16 14:39 被阅读0次

    上一篇 EventBus设计模式剖析(二)建造者模式

    EventBus:

    由开源组织greenrobot开发的事件发布-订阅总线库。

    设计模式:

    软件开发中问题的解决套路。

    观察者模式简介

    定义:定义对象间一种一对的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到广播通知并被自动更新。

    其实观察者模式(Observer Pattern)叫做发布-订阅模式更合适。发布者一旦更新消息,所有订阅者都能收到。观察者模式也很适用于UI事件触发和侦听,消息交换等场景
    Observer和Observable是JDK中的内置类型,若一个对象继承了Observer类,那么这段代码大概率用了观察者模式。

    EventBus类中的观察者模式

    EventBus作为事件发布-订阅总线库,必然使用了发布-订阅模式。
    继续使用之前文章的代码分析做分析。EventBus类通过register()方法注册成为订阅者(观察者)。

     // 1 注册广播
    EventBus.getDefault().register(EventBusActivity.this);
    

    EventBus通过post()方法进行发布,即拿到EventBus.getDefault()的线程自动成为发布者(被观察者)。EventBus以单例模式创建,就会变成长期跟随在这个Android应用的事件收发中心,贯穿全局。

     // 4 发送消息
    EventBus.getDefault().post(new MessageEvent("主线程发送过来的数据"));
    

    现在我们来看看如何register(注册)和如何post(发布)的。

    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    private final SubscriberMethodFinder subscriberMethodFinder;
    
    EventBus(EventBusBuilder builder) {
        //以事件类的class对象为键值,记录注册方法信息,值为一个Subscription的列表
        subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>(); 
        //以注册的类为键值,记录该类所注册的所有事件类型,值为一个Event的class对象的列表
        typesBySubscriber = new HashMap<Object, List<Class<?>>>();
    }
    
    //  注册给定的订阅服务器以接收事件,false表示不是粘性事件。
    public void register(Object subscriber) {
        register(subscriber, false, 0);
    }
    
    //  注册给定的订阅服务器以接收事件,并指定阅者优先级,从而影响事件交付顺序,false表示不是粘性事件。
    public void register(Object subscriber, int priority) {
        register(subscriber, false, priority);
    }
    
    // 同步方法,只能单线程访问,直到该线程释放同步锁,下一线程才可以访问
    private synchronized void register(Object subscriber, boolean sticky, int priority) {
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); // 订阅方法集合
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod, sticky, priority); // 订阅函数
        }
    }
    
    // 必须在同步块中调用 
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
        Class<?> eventType = subscriberMethod.eventType; // 获取订阅方法的事件类
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // // 创建订阅类 subscriptions集合,内部子项Subscription
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority); // new一个我们想要添加的 Subscription
        // 获取订阅了此事件类的所有订阅者信息列表,如果不存在则将其加入订阅者信息列表,如果已经存在此订阅者信息则抛出已注册的异常
        if (subscriptions == null) { // subscriptions集合为空
            subscriptions = new CopyOnWriteArrayList<Subscription>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) { // 若集合中已经有newSubscription,不必注册了,抛出异常
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);
            }
        }
    
        int size = subscriptions.size(); // subscriptions集合大小
        for (int i = 0; i <= size; i++) { // 遍历,若优先级较高,则插入;若优先级最低(i == size),尾部插入。
            if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
                subscriptions.add(i, newSubscription); 
                break;
            }
        }
    
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); // 获取此订阅者实例订阅的所有事件类的列表
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<Class<?>>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType); // 将此事件类加入 订阅者事件类列表中
        ......
    }
    

    订阅过程是在维护两个Map,一个是subscriptionsByEventType,另外一个是typesBySubscriber。首先来说subscriptionsByEventType:

    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    
    

    subscriptionsByEventType内部结构是Map<事件类,该事件的所有订阅者>。

    private final Map<Object, List<Class<?>>> typesBySubscriber;
    

    typesBySubscriber内部结构是Map<订阅者,该订阅者所订阅的所有事件>。
    其实这两个对象结构不同,但是所存储的信息是完全一致的。那为什么要重复定义呢?
    因为EventBus是一个发布订阅系统,subscriptionsByEventType是从发布者角度订制,而typesBySubscriber是从订阅者角度订制。

    基于观察者模式构建的其他代码

    1、Android的BroadcastRecevier广播机制
    2、ListView中的notifyDataSetChanged()方法

    参考文献

    1、设计模式|菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
    2、《Android源码设计模式解析与实战》何红辉,关爱民著
    3、蕉下孤客:https://www.jianshu.com/p/1b68ace4600a
    4、野生的安卓兽:https://www.jianshu.com/nb/10598547

    上一篇 EventBus设计模式剖析(二)建造者模式

    All is well.

    相关文章

      网友评论

        本文标题:EventBus设计模式剖析(三)观察者模式

        本文链接:https://www.haomeiwen.com/subject/idwnkctx.html