EventBus使用

来源:互联网 发布:mac怎么新建txt文件 编辑:程序博客网 时间:2024/06/05 15:05

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 通常在如下的生命周期中进行注册和反注册:

@Overridepublic void onStart() {    super.onStart();    EventBus.getDefault().register(this);}@Overridepublic 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 是一款典型的运行观察者模式的开源框架,设计巧妙,代码也通俗易懂,值得我们学习。





 
原创粉丝点击