欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

不,这只是个名字,一个代号,你可以叫,我也可以叫

程序员文章站 2024-03-18 20:24:40
...

最后编辑于2019年4月25日

提到事件总线我们总会想到EventBus和Otto,他们之间的区别是:
1、Otto可以使用@Produce的方式来发布事件;
2、EventBus提供了单例模式;
3、EventBus支持threadMode;
4、EventBus支持优先级;
5、EventBus支持编译时把订阅方法放到集合中等待调用合并成新的集合;
6、EventBus支持黏性事件。
今天这个吕秀才说死姬无命的故事就可以套用到黏性事件上。什么是黏性事件?先发送了事件后订阅对象,仍能触发订阅方法的事件就叫做黏性事件了。


一、先简单分析一下eventbus怎么处理普通事件的。


step1:订阅者注册,分为两步,一是查找订阅者的订阅方法,二是把方法按不同事件封装到一个集合中,并把方法按不同订阅对象封装到另一个集合中。
不,这只是个名字,一个代号,你可以叫,我也可以叫

 stepA:查找订阅者的方法,根据用户设置的ignoreGeneratedIndex,决定是通过反射的方法来获取订阅者方法,还是通过调用编译时生成的class中的方法来获取订阅者方法。
不,这只是个名字,一个代号,你可以叫,我也可以叫

 下面是通过反射的方法来获取订阅者方法:

不,这只是个名字,一个代号,你可以叫,我也可以叫

 而通过编译时生成的class中的方法来获取订阅者方法,则需要用户先使用以下代码:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// 这里是获取一个单例
EventBus eventBus = EventBus.getDefault();

这样就把订阅者及订阅者方法SimpleSubscriberInfo放到subscriberInfoIndexs里了,如下面两张图:
不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 通过findUsingInfo()方法分两步获取到订阅者方法,一、把subscriberInfoIndexes中的信息放到SubscriberInfo中,二、从SubscriberInfo中获取订阅者方法。如下面三张图:
不,这只是个名字,一个代号,你可以叫,我也可以叫

不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 stepB:把方法按不同事件封装到一个集合subscriptionsByEventType中,并把方法按不同订阅对象封装到另一个集合typesBySubscriber中:如下图:
不,这只是个名字,一个代号,你可以叫,我也可以叫

 

step2:事件的发送

通过post()、postSingleEvent()、postSingleEventForEventType()、postToSubscription()、invokeSubscriber()几个方法的传递,最终事件的发送触发了订阅方法的调用,如下面几张图:
不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 

step3: 订阅者取消注册

分为两步,把该对象下的按事件分类的订阅从subscriptionsByEventType中移除,把该订阅对象下的订阅从typesBySubscriber中移除,如下面两张图:
不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 

 eventbus怎么处理普通事件的简易过程就讲完了(我只是想讲一个黏性事件的,结果讲了这么多,暴汗2333)。
 

二、黏性事件的处理

先发送了事件后注册订阅对象,仍能触发订阅方法的事件就叫做黏性事件了。
后注册订阅怎么还能触发呢?其实这个时候黏性事件反而成了订阅对象,当注册时就会调用黏性事件相关的订阅方法。
不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫
不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

 不,这只是个名字,一个代号,你可以叫,我也可以叫

不,这只是个名字,一个代号,你可以叫订阅对象,我也可以叫订阅对象。

三、再举个例子

Person都有YoungState、OldState两种状态可以这么写:

public class Person {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void brush() {
        state.brush();
    }
}

public interface State {
    void brush();
}

public class YoungState implements State {
    @Override
    public void brush() {
        System.out.println("年轻人刷牙");
    }
}

public class OldState implements State {
    @Override
    public void brush() {
        System.out.println("老年人刷牙");
    }
}

在此基础上可以很轻松地加一个childState:

public class ChildState implements State {
    @Override
    public void brush() {
        System.out.println("小孩刷牙");
    }
}

 但是如果要你增加wash、eat、run几个方法呢,像下面这样吗?

public class Person {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void brush() {
        state.brush();
    }

    public void wash() {
        state.wash();
    }

    public void eat() {
        state.eat();
    }

    public void run() {
        state.run();
    }
}
public interface State {
    void brush();
    void wash();
    void eat();
    void run();
}
public class YoungState implements State {
    @Override
    public void brush() {
        System.out.println("年轻人刷牙");
    }

    @Override
    public void wash() {
        System.out.println("年轻人洗脸");
    }

    @Override
    public void eat() {
        System.out.println("年轻人吃饭");
    }

    @Override
    public void run() {
        System.out.println("年轻人跑步");
    }
}
public class OldState implements State {
    @Override
    public void brush() {
        System.out.println("老年人刷牙");
    }

    @Override
    public void wash() {
        System.out.println("老年人洗脸");
    }

    @Override
    public void eat() {
        System.out.println("老年人吃饭");
    }

    @Override
    public void run() {
        System.out.println("老年人跑步");
    }
}

但其实还可以换个角度,把brush、wash、eat、run当作一种状态:

public class Person {
    private State state;

    public void setState(State state) {
        this.state = state;
    }

    public void young() {
        state.young();
    }

    public void old() {
        state.old();
    }
}
public interface State {
    void young();
    void old();
}
public class BrushState implements State {
    @Override
    public void young() {
        System.out.println("年轻人刷牙");
    }

    @Override
    public void old() {
        System.out.println("老年人刷牙");
    }
}
public class WashState implements State {
    @Override
    public void young() {
        System.out.println("年轻人洗脸");
    }

    @Override
    public void old() {
        System.out.println("老年人洗脸");
    }
}
public class EatState implements State {
    @Override
    public void young() {
        System.out.println("年轻人吃饭");
    }

    @Override
    public void old() {
        System.out.println("老年人吃饭");
    }
}
public class RunState implements State {
    @Override
    public void young() {
        System.out.println("年轻人跑步");
    }

    @Override
    public void old() {
        System.out.println("老年人跑步");
    }
}

 不,这只是个名字,一个代号,你可以叫状态,我也可以叫状态。

四、再再举个例子

AIDL中客户端可以变为服务端,服务端也可以变为客户端,通过aidl调用远程服务 。