BroadcastReceiver
本质上是一个监听器,分为接收者和发送者。用于监听(接收)应用发出的广播消息,并做出响应。可用于进程间通信、线程间通信和监听系统的特定时间(如:电话呼入,网络状态变更等)。
-
使用观察者模式:基于消息的发布/订阅事件模型。
-
常用做与android 系统事件的监听和交互。
-
消耗时间、空间较多,在onRecieve()方法内可以获得Context和Intent参数,通过这两个方法,可以调用AndroidSDK中的很多方法,属于重量级组件。
-
可跨进程通信。
Eventbus
针对android跨进程、线程通信的优化方案,一定程度上可以代替广播、handler、Intent。
优点
- 调度灵活,不依赖于context。
- 可继承。
- 有事件优先级。
- 粘性事件机制。
- 量级较轻。
1. 实现原理
-
getDefault():通过懒汉单例模式获取到对象
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
在new对象时,使用builder模式:
EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); 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); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }
-
register()实现如下:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//通过反射的方式获取到所有通过注解注册的回调方法 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod);//这里是具体的注册方法 } } }
Subscribe():
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 { if (subscriptions.contains(newSubscription)) {//若该事件(注册者和消费方法)已注册,则抛异常 throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } 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; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);//获取该订阅者下的所有订阅事件 if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType);//将本事件添加进触发事件列表中 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(); for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
以上就是EventBus注册时的逻辑,接下来我们看看发布事件的时候的逻辑:
-
post():
public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue;//获取当前线程的消息队列 eventQueue.add(event);//将本事件添加进消息队列中 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()) {//循环遍历事件队列(在这儿可以类比handler机制不过不是死循环,也不存在阻塞,每post一次就进行判断,是否处于posting) postSingleEvent(eventQueue.remove(0), postingState);//主要的消费逻辑 } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
这个currentPostingThreadState是做什么的呢,我们可以看一下它的声明和实现:
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
这里使用了ThreadLocal,说明在每个线程里都会有这个对象的副本。我们接着往下看PostingThreadState是维护什么的类:
final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>();//事件队列,用一个list维护 boolean isPosting;//是否在发布事件(就是之后的循环遍历是否在执行) boolean isMainThread;//是否为主线程,通过判断当前looper是否为MainLooper Subscription subscription;//当前的订阅类,上面有说明 Object event;//当前正在处理的事件 boolean canceled;//当前事件是否被取消 }
我们继续看postSingleEvent()方法,这里是事件消费的主要逻辑:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { Class<?> clazz = eventTypes.get(h); subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } if (!subscriptionFound) { if (logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
这里可以看到最终都会回调postSingleEventForEventType()这个方法,我们继续看这个方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event;//当前正在处理的事件 postingState.subscription = subscription;//当前正在轮询的订阅事件 boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread);//事件处理方法 aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
我们接着看:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) {//这里就是处理线程模式的不同策略 case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
我们从默认的POSTING模式往下看:
void invokeSubscriber(PendingPost pendingPost) { Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); } }
我们接着看:
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//最终是通过反射的方法调用事件的处理 } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
这样我们可以知道,最后调用方法是通过反射来调用与之对应的消费事件的方法。
网友评论