EventBus简单介绍
- Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.
- Android优化的事件总线,简化了活动,片段,线程,服务等之间的通信。较少的代码,更好的质量。
使用EventBus(事件总线 - 事件分发)分成以下几步:
- 创建事件类
- 声明订阅方法
- 注册订阅者
- 发送订阅事件
- 注销订阅者
按上面步骤看源码(EventBus源码链接https://github.com/greenrobot/EventBus/)
创建事件类
创建一个普通的实体类就可以了
public class User {
private String name;
private int age;
private String addr;
public User() {
}
...setter...
...getter...
声明订阅方法
这里对订阅的事件做处理
@Subscribe(threadMode= ThreadMode.MAIN)
public voidgetUser(User user){
textView.setText(user.getName() + "\n" + user.getAge() + "\n" + user.getAddr());//对事件的处理
}
对照源码看Subscribe注解,有三个值。
ThreadMode:订阅方法运行的线程
sticky:是否为粘性事件
priority:优先级
具体的用途,在后面代码中能体现出来。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
boolean sticky() default false;
int priority() default 0;
}
注册成为订阅者
先从默认设置开始,看一下是怎样成为订阅者的。
EventBus.getDefault().register(this);
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
单例模式,新建EventBus对象。看看EventBus构造方法。
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
this(DEFAULT_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;
}
采用的是构造者模式,默认设置先不关注。关注一下这几个。
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map
subscriptionsByEventType
typesBySubscriber
stickyEvents
具体用来做什么,后面再说。
注册成为订阅者
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
//找到订阅者对象 中的所有 订阅方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethod 用来 保存 订阅方法 信息 的一个类
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;//订阅方法运行的线程
final Class> eventType;//事件类
final int priority;//优先级
final boolean sticky;//是否为粘性事件
/** Used for efficient comparison */
String methodString;
...
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
获取订阅者对象中所有 订阅方法。
有两种方式:
1、subscriberMethods = findUsingReflection(subscriberClass);
2、subscriberMethods = findUsingInfo(subscriberClass);
分别看一下。
private List findUsingInfo(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
通过生成的注解类来获取订阅方法
private List findUsingReflection(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
使用反射获取订阅方法
private List getMethodsAndRelease(FindState findState) {
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
返回订阅者中的 所有订阅方法
final class Subscription {
final Object subscriber;
final SubscriberMethod subscriberMethod;
/**
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
Subscription是一个同时持有 订阅者、订阅者中的订阅方法 的对象。
下面看看最主要的订阅方法 - subscribe()
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
//以事件类为key、Subscription为value,存到Map中。
//就是让事件类和订阅者+订阅方法关联起来。
//保证发送事件时,能找到相应的订阅者+订阅方法。
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> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
//把订阅者、事件放进typesBySubscriber这个Map中
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).
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, 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);
}
}
}
在subscribe方法中,做了几件事情:
1、subscriptionsByEventType.put(eventType, subscriptions);
以事件类为key、Subscription为value,存到Map中。就是让事件类和订阅者+订阅方法关联起来。保证发送事件时,能找到相应的订阅者+订阅方法。
2、typesBySubscriber.put(subscriber, subscribedEvents);以订阅者为key,事件类为value,存到Map中
3、处理粘性事件(粘性事件:1、允许先发送事件、后注册订阅者 2、粘性事件 只会接收最近一次发送的粘性事件)
subscriptionsByEventType、typesBySubscriber、stickyEvents就是前面提到需要关注的三个。
发送订阅事件
/** Posts the given event to the event bus. */
public void post(Object event) {
//获得线程中唯一的postingState
PostingThreadState postingState = currentPostingThreadState.get();
//获取事件列表
List
private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
final static class PostingThreadState {
// 当前线程的事件队列
final List
- currentPostingThreadState是一个ThreadLocal,保存线程中的变量,具有唯一性。
- 所以 PostingThreadState postingState = currentPostingThreadState.get();获得了唯一的PostingThreadState
- PostingThreadState 是定义的一个内部类,用来封装post事件线程的一些信息(在哪个线程中调用post(Object event),就会通过currentPostingThreadState.get()方法去获取PostingThreadState)。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List> 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));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList 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) {
// 获取订阅方法 设置的 运行线程(Subscribe 注解 threadMode)
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//默认设置,在post事件线程 反射调用订阅方法
invokeSubscriber(subscription, event);
break;
case MAIN:
// 设置为主线程运行
// 若post 也在主线程 则直接 反射调用订阅方法
// 否则 添加到mainThreadPoster 的队列中
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);
}
}
获取订阅方法 设置的 运行线程(Subscribe 注解 threadMode)
1、POSTING(默认情况下),直接会在 post事件 线程中 反射调用 订阅方法
2、MAIN 若post事件 也在主线程运行 则直接反射调用 订阅方法。否则添加到mainThreadPoster队列中执行
3、BACKGROUND
4、ASYNC
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);
}
}
反射调用。事件发送流程结束。
注销订阅者
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
// typesBySubscriber是一个HashMap,在注册订阅者的时候,保存了订阅者(key)、事件类(value)。
// 获得 该 订阅者 订阅的所有 事件类
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
// 遍历所有 事件类
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
// 从HashMap中移除 订阅者
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
// 根据 事件类 从subscriptionsByEventType中获取相应的 subscriptions 集合
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
//遍历所有的subscriptions,逐一移除
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
注销订阅者:
1、获取 该订阅者订阅的 所有 事件类
2、从subscriptionsByEventType中 移除subscription
3、从typesBySubscriber中移除 订阅者
下面分别来看一下
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
HandlerPoster
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
BackgroundPoster
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
AsyncPoster
class AsyncPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
}
EventBus事件总线的框架,总体思路大致这样,当然,一个如此优秀的框架,还有很多细节需要学习:比如说并发控制、职责分离、设计模式等,以后有机会再慢慢学习。
总结
- EventBus是采用 发布-订阅 模式,消息的媒介 是 事件类。
- 注册订阅者时,以key(事件类) 、map(订阅者+订阅方法)保存在一个HashMap中。
- 发送订阅事件时,会获取线程中的事件列表,根据事件类型 获取所有的订阅者+订阅方法,反射调用订阅方法。
- 注销订阅者时,移除订阅者。
几点
- 采用EventBus能很方便进行事件传递,很简洁。但是会导致业务逻辑过于分散,不熟悉代码可能很多地方注意不到。
- 参考文章http://www.jianshu.com/p/f54514f8cf79
- 参考文章http://www.jianshu.com/p/bda4ed3017ba(以上两位写的更简单易懂,推荐阅读)
- 源码https://github.com/greenrobot/EventBus/