github源码分享:https://github.com/greenrobot/EventBus
官方图解:
EventBus是Android和Java的发布/订阅事件总线。
EventBus优势:
1、简化了组件之间的通信:
将事件发送者和接收者分离
在活动,片段和后台线程中表现良好
避免复杂且容易出错的依赖关系和生命周期问题
2、使您的代码更简洁
3、很快
4、很小(约50kb)
5、已经通过100,000,000+安装的应用程序在实践中得到证实
6、具有交付线程,用户优先级等高级功能;
总结:
EventBus的使用比较简单,可以按照官网图的方式来进行理解。EventBus相当于邮箱,发布者直接把信息放到信箱,信箱会自动把信息发给订阅了的人。
这里简单梳理一下EventBus的主要逻辑:
1、EventBus对象的构建,使用单列模式创建
2、注册事件,包含粘性事件
3、发布消息
4、接受消息
5、反注册事件,避免内存泄漏
(一)、EventBus构造方法原理
这里就简单的使用单例模式实现
EventBus.java
private static EventBus instance;
public static EventBus getDefault() {
if (instance == null) {
synchronized (EventBus.class) {
if (instance == null) {
instance = new EventBus();
}
}
}
return instance;
}
(二)、注册事件
注册就是将此类中的所有的带Subscriber注解的方法缓存起来,以便发布消息时调用;
我们也是简单的模拟实现注册,不包含粘性事件的注册
需求:从AActivity跳转到BActivity中,在BActivity中发布消息给AActivity;
//比如在AActivity接受事件,我们就在AActivity中注册一个接收消息的方法
如:
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void handleMessages(EventBean eventBean) {
Log.d("======>", eventBean.toString());
Log.d("======", "send: MainActivity " + Thread.currentThread().getName());
}
Subscribe是一个注解类,用来标记一个方法
Subscribe.java
@Documented
@Retention(RetentionPolicy.RUNTIME)// 表示为运行时注解
@Target({ElementType.METHOD})
public @interface Subscribe {
// 指定事件订阅方法的线程模式,即在那个线程执行事件订阅方法处理事件,默认为POSTING
ThreadMode threadMode() default ThreadMode.POSTING;
// 是否支持粘性事件,默认为false
boolean sticky() default false;
// 指定事件订阅方法的优先级,默认为0,如果多个事件订阅方法可以接收相同事件的,则优先级高的先接收到事件
int priority() default 0;
}
ThreadMode是一个枚举类,用来标记此方法在那个线程执行
ThreadMode.java
public enum ThreadMode {
POSTING,//默认的线程模式,在那个线程发送事件就在对应线程处理事件,避免了线程切换,效率高。
MAIN,//如在主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
MAIN_ORDERED,//无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
BACKGROUND,//如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的线程处理事件。
ASYNC//无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
}
private Map<Object, List<SubscriberMethod>> cacheMap;// 用来缓存注册\订阅的事件
public void register(Object subscriber) {
// 检查此类是否已经注册
List<SubscriberMethod> subscriberMethods = cacheMap.get(subscriber);
if (subscriberMethods == null) {
subscriberMethods = findSubscriberMethods(subscriber);
cacheMap.put(subscriber, subscriberMethods);
}
}
/**
* 查找此类以及父类中所有带Subscriber注释的方法
* @param subscriber
* @return
*/
private List<SubscriberMethod> findSubscriberMethods(Object subscriber) {
List<SubscriberMethod> list = new ArrayList<>();
Class<?> clazz = subscriber.getClass();
while (clazz != null) {
String name = clazz.getName();
// 过滤系统类
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
break;
}
Method[] methods = clazz.getDeclaredMethods();// 获取此类中所有的的方法(包含继承父类中的)
for (Method method : methods) {
Subscribe annotation = method.getAnnotation(Subscribe.class);// 找到方法上的注解参数
if (annotation == null) {
continue;
}
//获取所有带有Subscribe注解的方法中的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {// 只记录带有一个参数的方法
Log.e("error", "EventBus only support one para");
continue;
}
ThreadMode threadMode = annotation.threadMode();
SubscriberMethod subscriberMethod = new SubscriberMethod(method, parameterTypes[0], threadMode, 0, false);
list.add(subscriberMethod);
}
clazz = clazz.getSuperclass();
}
return list;
}
SubscriberMethod.java 带有注解的方法对象
public class SubscriberMethod {
private Method method;
private ThreadMode threadMode;
private Class<?> eventType;
private int priority;
private boolean sticky;
/**
* Used for efficient comparison
*/
String methodString;
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;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof SubscriberMethod) {
checkMethodString();
SubscriberMethod otherSubscriberMethod = (SubscriberMethod) other;
otherSubscriberMethod.checkMethodString();
// Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
return methodString.equals(otherSubscriberMethod.methodString);
} else {
return false;
}
}
private synchronized void checkMethodString() {
if (methodString == null) {
// Method.toString has more overhead, just take relevant parts of the method
StringBuilder builder = new StringBuilder(64);
builder.append(method.getDeclaringClass().getName());
builder.append('#').append(method.getName());
builder.append('(').append(eventType.getName());
methodString = builder.toString();
}
}
@Override
public int hashCode() {
return method.hashCode();
}
public Method getMethod() {
return method;
}
public ThreadMode getThreadMode() {
return threadMode;
}
public Class<?> getEventType() {
return eventType;
}
public int getPriority() {
return priority;
}
public boolean isSticky() {
return sticky;
}
public String getMethodString() {
return methodString;
}
}
以上就是事件注册\订阅的完整流程
(三)、发布消息
SecondActivity.java中任意位置
EventBus.getDefault().post(new EventBean("EventBusMassage", 111111111));
EventBus.java
public void post(final Object obj) {
// 从注册事件中循环查询
Set<Object> objects = cacheMap.keySet();
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()) {
final Object next = iterator.next();
List<SubscriberMethod> list = cacheMap.get(next);
for (final SubscriberMethod subsMethod : list) {
// 获取到的类的类型是否和传入或者发送消息的类对象类型相同
if (subsMethod.getEventType().isAssignableFrom(obj.getClass())) {
switch (subsMethod.getThreadMode()) {
case MAIN:
// 主线程---》主线程
if (Looper.myLooper() == Looper.getMainLooper()) {
invoke(subsMethod, next, obj);
} else { // 子线程---》主线程
mHandler.post(new Runnable() {
@Override
public void run() {
invoke(subsMethod, next, obj);
}
});
}
break;
case BACKGROUND:
// 主线程---》子线程
if (Looper.myLooper() == Looper.getMainLooper()) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
@Override
public void run() {
invoke(subsMethod, next, obj);
}
});
} else { // 子线程---》子线程
invoke(subsMethod, next, obj);
}
break;
}
}
}
}
}
// 方法调用并执行
private void invoke(SubscriberMethod subsMethod, Object next, Object obj) {
Method method = subsMethod.getMethod();
try {
method.invoke(next, obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
(四)、接受消息
MainActivity.java
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void handleMessages(EventBean eventBean) {
Log.d("======>", eventBean.toString());
Log.d("======", "handleMessages: MainActivity " + Thread.currentThread().getName());
}
(五)、注销事件
MainActivity.java
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
EventBus.java
// 注销事件
public void unregister(Object subscriber) {
List<SubscriberMethod> subscribedTypes = cacheMap.get(subscriber);
if (subscribedTypes != null) {
cacheMap.remove(subscriber);
} else {
Log.e("error", "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}