事件总线
基本上都是观察者模式的扩展
Google/Guava:Guava是一个庞大的库,EventBus只是它附带的一个小功能,因此实际项目中使用并不多
greenrobot/EventBus:简洁体量小
square/otto:修改自 Guava,官方已经标记为过时了,并推荐使用RxJava代替它。
RxJava:主要用于响应式编程。
使用
EventBus
1、注册和注销:
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
这里请注意,activity以及fragment的生命周期,如果不了解,可以再深度学习一下。
2、定义事件,也就是实体类:
public class MessageEvent {
String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
3、发布事件:
EventBus.getDefault().post(new MessageEvent(message));
4、处理事件:
@Subscribe
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this, "收到消息", Toast.LENGTH_SHORT).show();
Log.i("111","来自PostActivity消息"+event.getMessage());
tx.setText(event.getMessage());
}
这是官网的大致流程。注意:如果要把一个Event发送到一个还没有初始化的Activity/Fragment,即尚未订阅事件(也就是说在post之前,如果该Activity/Fragment还没有被初始化过,请使用postSticky())。那么请使用postSticky()方法,并将@Subscribe改为@Subscribe(sticky = true)。
EventBus
EvenBus的使用较为简单,但是很实用。一般查看源码有一个比较实用的方法:追踪使用方法,进而将整个框架的流程弄清楚,源码自然而然就清楚了。
1、这里注册为第一步:EventBus.getDefault().register(this),EventBus采用的是单例设计模式,通过getDefault()取得当前实例,register中的方法如下:
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//核心方法1
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//核心方法2
subscribe(subscriber, subscriberMethod);
}
}
}
可以看到首先通过反射得到了订阅类的类型,接下来是组装了一个List,这里看一下SubscriberMethod是什么:
public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
哦,一看,原来是订阅信息的实体包装类。回到主方法,首先追踪核心方法1,findSubscriberMethods(subscriberClass)方法,追踪进去:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//这里首先从缓存中获取
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//是否忽略注解器生成的MyEventBusIndex类
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;
}
}
进入:
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findUsingReflectionInSingleClass(findState);
findState.moveToSuperclass();//将subscriberClass向上转型为父类,比如某一个DemoActivity.class,转为Activity.class
}
return getMethodsAndRelease(findState);//重新组装
}
这里有一个FindState内部类,看其构造器以及类属性:
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
主要存储的是方法是一系列订阅方法。追踪findUsingReflectionInSingleClass(findState):
private void findUsingReflectionInSingleClass(FindState findState) {
//定义一个Method数组
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
//取得类中的所有的方法,比如在Activity中,onCreate,onStart方法都会取到
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)) {
//省略
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
//省略
}
}
}
回到getMethodsAndRelease(findState)方法;
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> 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;
}
构造了一个List,同时释放findState资源,并返回List。至此已经取得了所有所有被@Subscribe注解标记的方法信息。
接下来是执行核心方法2:
主要作用是将SubscriberMethod填充到两个Map中,
//订阅者和订阅方法一一对应的组合成一个Subscription类
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
//key:订阅EventType,也就是传递和接收时的实体信息类EventType比如MessageEvent; values:所有订阅了该类型的Subscription集合。主要用于在post中执行时取出
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//key订阅者;values订阅EventType集合,主要用于判断是否注册成功以及注销
private final Map<Object, List<Class<?>>> typesBySubscriber;
同时定义了Sticky策略的处理方法–二次调用:
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
通俗的来说订阅者就是任意一个注册了的Activity/Fragment,这里就可以看出单例模式设计的威力。
2、到这里注册已经基本完成了,接下来是事件发送
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()) {
//核心代码
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
追踪postSingleEvent来到:postSingleEventForEventType,核心代码如下:
//通过EventType取得一个Subscription的List
subscriptions = subscriptionsByEventType.get(eventClass);
//省略了循环List取得subscription
postToSubscription(subscription, event, postingState.isMainThread);
然后来到下一步:
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);
}
}
最终的执行如下,使用反射执行方法:
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);
}
}
到此为止,基本流程已经走通,还有一个Sticky策略,也是类似,postSticky()方法只是异步维护了一个stickyEvents,最终还是要调用post方法,只是此时register还没有初始化,所以订阅者和订阅方法都为空。
RXJava:
基本上是跟Retrofit配合。