EventBus的源码详解与架构分析,使用EventBus会造成什么弊端,带你复现整个思路历程

post(Object object);

先看看初始化部分,看看如何实现单例的(可选的)。

// volatile 这里是需要重视的,这个关键字保证了defaultInstance在不同线程间的可见性,也就是说在多线程环境下,看到的仍然是最新修改的值。

static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
// 这一步不存在线程问题,volatile保证了。如果没有defaultInstance实例化出来,
if (defaultInstance == null) {
synchronized (EventBus.class) {
// 进入同步块的时候,不能保证defaultInstance没有被实例化出来,所以需要进行double-check
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}

// 这里实现的时候,考虑的是defaultInstance 不一定是每个人都需要创建的,否则没必要使用lazy的实现方式
// 下面是一种实现方式
static {
defaultInstance = new EventBus();
}

EventBus实现了EventBusBuilder,通过Builder的方式使得构建的时候更加容易

public static EventBusBuilder builder() {
return new EventBusBuilder();
}

下面重点看看register(Object subscriber, boolean sticky, int priority)方法

private synchronized void register(Object subscriber, boolean sticky, int priority) {
// 用 subscriberMethodFinder 提供的方法,找到在 subscriber 这个类里面,订阅的内容。
List subscriberMethods
= subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 遍历这些方法,subscribe 这些事件
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}

findSubscriberMethods 这个方法是实现 EventBus 的核心代码,这里面包含了 EventBus 隐式定义的交互协议。从这个方法里面,可以看到如何争取地使用EventBus。

List findSubscriberMethods(Class<?> subscriberClass) {
String key = subscriberClass.getName();
List subscriberMethods;
// 如果这个 Class 对应的方法被缓存,直接返回。
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
// 这个方法其实可以放在 前面的 synchronized 模块里面
if (subscriberMethods != null) {
return subscriberMethods;
}
subscriberMethods = new ArrayList();
Class<?> clazz = subscriberClass;
HashSet eventTypesFound = new HashSet();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
// 跳过JDK里面的类
if (name.startsWith(“java.”) || name.startsWith(“javax.”) || name.startsWith(“android.”)) {
// Skip system classes, this just degrades performance
break;
}

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// 获取所有声明的方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 方法是 Public 的
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
ThreadMode threadMode;

// 方法的前缀是否是 ‘OnEvent’, 如果是‘OnEvent’,查看后面的字符串,这里定义了 4 种基本类型
// ThreadModel 会在后面介绍
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals(“MainThread”)) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals(“BackgroundThread”)) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals(“Async”)) {
threadMode = ThreadMode.Async;
} else {
if (skipMethodVerificationForClasses.containsKey(clazz)) {
continue;
} else {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
}

// 获取参数类型
Class<?> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append(’>’).append(eventType.getName());
// 得到类似于一个句柄的东西,比如 onEventMainThread>DownloadInfo
String methodKey = methodKeyBuilder.toString();
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + “.”

  • methodName);
    }
    }
    }
    // 这里要为 EventBus 点个赞了,EventBus 是支持继承的
    clazz = clazz.getSuperclass();
    }
    if (subscriberMethods.isEmpty()) {
    throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
  • ON_EVENT_METHOD_NAME);
    } else {
    synchronized (methodCache) {
    methodCache.put(key, subscriberMethods);
    }
    return subscriberMethods;
    }
    }

现在看下如何把 subscriberClass 里面的内容订阅到 EventBus 里面去。

// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class<?> eventType = subscriberMethod.eventType;
// 获取订阅了某种类型数据的 Subscription 。 使用了 CopyOnWriteArrayList ,这个是线程安全的,
// CopyOnWriteArrayList 会在更新的时候,重新生成一份 copy,其他线程使用的是
// copy,不存在什么线程安全性的问题。
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
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);
    }
    }

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);

int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
// 根据优先级进行插入,其实这里可以替换为优先级队列的
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}

List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

if (sticky) {
// 是否支持继承,这个可以在 Builder 的时候指定,如果不支持,那么可能有20%以上的性能提升
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).

最后

Android学习是一条漫长的道路,我们要学习的东西不仅仅只有表面的 技术,还要深入底层,弄明白下面的 原理,只有这样,我们才能够提高自己的竞争力,在当今这个竞争激烈的世界里立足。

人生不可能一帆风顺,有高峰自然有低谷,要相信,那些打不倒我们的,终将使我们更强大,要做自己的摆渡人。

我把自己这段时间整理的Android最重要最热门的学习方向资料放在了我的GitHub,里面还有不同方向的自学编程路线、面试题集合/面经、及系列技术文章等。

资源持续更新中,欢迎大家一起学习和探讨。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值