EventBus使用

EventBus 是一种为 Android 而优化设计的发布/订阅事件总线

有了这个,对于一个事件,你只要关心发送和接收就行了,而其中的收集、分发等都交给 EventBus 来处理,你不需要做任何事

使用方法

首先导入依赖包

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })

    compile 'org.greenrobot:eventbus:3.0.0'
    testCompile 'junit:junit:4.12'
}
第一步,定义一个事件类 MyEvent

public class MyEvent {
    private String msg;//需要传递的数据(可以是复杂bean对象)

    public MyEvent(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}



定义一个订阅方法,可以使用 @Subscribe 注解来指定订阅方法所在的线程:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MyEvent event) {
    String msg=event.getMsg();//获取传递过来的信息
    };

注册和反注册你的订阅方法。比如在 Android 中,Activity 和 Fragment 通常在如下的生命周期中进行注册和反注册:

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    super.onStop();
    EventBus.getDefault().unregister(this);
}

3.发送事件:

 EventBus.getDefault().post(new MyEvent("msg"));

使用非常简单


EventBus 原理分析



EventBus.getDefault()

来看源码

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
        private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        private final Map<Class<?>, Object> stickyEvents;
        public static EventBus getDefault() {
            if (defaultInstance == null) {
                synchronized (EventBus.class) {
                    if (defaultInstance == null) {
                        defaultInstance = new EventBus();
                    }
                }
            }
            return defaultInstance;
            }
        /**
         * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
         * central bus, consider {@link #getDefault()}.
         */
         public EventBus() {
            this(DEFAULT_BUILDER);
            }
        EventBus(EventBusBuilder builder) {
            // key 为事件的类型,value 为所有订阅该事件类型的订阅者集合
            subscriptionsByEventType = new HashMap<>();
            // key 为某个订阅者,value 为该订阅者所有的事件类型
            typesBySubscriber = new HashMap<>();
            // 粘性事件的集合,key 为事件的类型,value 为该事件的对象
            stickyEvents = new ConcurrentHashMap<>();
            // 主线程事件发送者
            mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
            // 子线程事件发送者
            backgroundPoster = new BackgroundPoster(this);
            // 异步线程事件发送者
            asyncPoster = new AsyncPoster(this);
            // 索引类的数量
            indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
            // 订阅方法查找者
            subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                    builder.strictMethodVerification, builder.ignoreGeneratedIndex);
            // 是否打印订阅者异常的日志,默认为 true
            logSubscriberExceptions = builder.logSubscriberExceptions;
            // 是否打印没有订阅者的异常日志,默认为 true
            logNoSubscriberMessages = builder.logNoSubscriberMessages;
            // 是否允许发送 SubscriberExceptionEvent ,默认为 true
            sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
            // 是否允许发送 sendNoSubscriberEvent ,默认为 true
            sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
            // 是否允许抛出订阅者的异常,默认是 false
            throwSubscriberException = builder.throwSubscriberException;
            // 是否支持事件继承,默认是 true
            eventInheritance = builder.eventInheritance;
            // 创建线程池
            executorService = builder.executorService;
            }

平时的我们经常调用的 EventBus.getDefault() 代码,其实是获取了 EventBus 类的单例。在初始化这块调用的是EventBusBuilder的默认参数,在 EventBus 构造器中初始化了一堆的成员变量.

EventBus.register(Object subscriber)

事件订阅者必须调用 register(Object subscriber) 方法来进行注册,一起来看看在 register(Object subscriber) 中到底做了一些什么:

public void register(Object subscriber) {
            // 得到订阅者的类 class
            Class<?> subscriberClass = subscriber.getClass();
            // 找到该 class 下所有的订阅方法
            List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
            synchronized (this) {
                for (SubscriberMethod subscriberMethod : subscriberMethods) {        
                    subscribe(subscriber, subscriberMethod);
                }
            }
            }


在 register(Object subscriber) 中,利用 subscriberMethodFinder.findSubscriberMethods 方法找到订阅者 class 下所有的订阅方法,然后用 for 循环建立订阅关系。

然后就是轮到了 subscribe(subscriber, subscriberMethod) 方法:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
            // 得到订阅方法的事件类型
            Class<?> eventType = subscriberMethod.eventType;
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
            // 根据订阅方法的事件类型得到所有订阅该事件类型的订阅者集合
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            } else {
                // 如果 subscriptions 已经包含了,抛出异常
                if (subscriptions.contains(newSubscription)) {
                    throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                            + eventType);
                }
            }
            // 根据该 subscriberMethod 优先级插入到 subscriptions 中
            int size = subscriptions.size();
            for (int i = 0; i <= size; i++) {
                if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                    subscriptions.add(i, newSubscription);
                    break;
                }
            }
            // 放入 subscribedEvents 中,key:订阅者  value:该订阅者的所有订阅事件的类型
            List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
            if (subscribedEvents == null) {
                subscribedEvents = new ArrayList<>();
                typesBySubscriber.put(subscriber, subscribedEvents);
            }
            subscribedEvents.add(eventType);
            // 如果订阅的方法支持 sticky
            if (subscriberMethod.sticky) {
                // 如果支持事件继承
                if (eventInheritance) {
                    // Existing sticky events of all subclasses of eventType have to be considered.
                    // Note: Iterating over all events may be inefficient with lots of sticky events,
                    // thus data structure should be changed to allow a more efficient lookup
                    // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                    Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                    // 遍历 stickyEvents
                    for (Map.Entry<Class<?>, Object> entry : entries) {
                        Class<?> candidateEventType = entry.getKey();
                        // 判断 eventType 类型是否是 candidateEventType 的父类
                        if (eventType.isAssignableFrom(candidateEventType)) {
                            // 得到对应 eventType 的子类事件,类型为 candidateEventType
                            Object stickyEvent = entry.getValue();
                            // 发送粘性事件给 newSubscription
                            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                        }
                    }
                } else {
                    // 拿到之前 sticky 的事件,然后发送给 newSubscription
                    Object stickyEvent = stickyEvents.get(eventType);
                    // 发送粘性事件给 newSubscription
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
            }

其实 subscribe(subscriber, subscriberMethod) 方法主要就做了三件事:

得到 subscriptions ,然后根据优先级把 subscriberMethod 插入到 subscriptions 中;
将 eventType 放入到 subscribedEvents 中;
如果订阅方法支持 sticky ,那么发送相关的粘性事件。

unregister(Object subscriber)

首先从typesBySubscriber获取当前订阅者,然后找到此订阅者的所有类型,将此订阅者的所有类型从subscriptionsByEventType表里删除。接着再把此订阅者从typesBySubscriber中删除

看看 unregister(Object subscriber) 的源码:

public synchronized void unregister(Object subscriber) {
            // 通过 subscriber 来找到 subscribedTypes
            List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
            if (subscribedTypes != null) {
                for (Class<?> eventType : subscribedTypes) {
                    // 解除每个订阅的事件类型
                    unsubscribeByEventType(subscriber, eventType);
                }
                // 从 typesBySubscriber 中移除
                typesBySubscriber.remove(subscriber);
            } else {
                Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
            }
            }
        private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
            List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions != null) {
                int size = subscriptions.size();
                for (int i = 0; i < size; i++) {
                    Subscription subscription = subscriptions.get(i);
                    if (subscription.subscriber == subscriber) {
                        subscription.active = false;
                        subscriptions.remove(i);
                        i--;
                        size--;
                    }
                }
            }
            }

post(Object event)

分析下发送事件 post(Object event) 的源码:

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
            @Override
            protected PostingThreadState initialValue() {
                return new PostingThreadState();
            }
            };
        public void post(Object event) {
            // 得到当前线程的 postingState
            PostingThreadState postingState = currentPostingThreadState.get();
            // 加入到队列中
            List<Object> eventQueue = postingState.eventQueue;
            eventQueue.add(event);
            // 如果没有持续在发送事件,那么开始发送事件并一直保持发送ing
            if (!postingState.isPosting) {
                postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                postingState.isPosting = true;
                if (postingState.canceled) {
                    throw new EventBusException("Internal error. Abort state was not reset");
                }
                try {
                    while (!eventQueue.isEmpty()) {
                        // 发送单个事件
                        postSingleEvent(eventQueue.remove(0), postingState);
                    }
                } finally {
                    postingState.isPosting = false;
                    postingState.isMainThread = false;
                }
            }
            }
在 post(Object event) 中,首先根据 currentPostingThreadState 获取当前线程状态 postingState 。currentPostingThreadState 其实就是一个 ThreadLocal 类的对象,不同的线程根据自己独有的索引值可以得到相应属于自己的 postingState 数据。然后把事件 event 加入到 eventQueue 队列中排队。只要 eventQueue 不为空,就不间断地发送事件

EventBus 是一款典型的运行观察者模式的开源框架,设计巧妙,代码也通俗易懂,值得我们学习。






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

揽m月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值