哎呀呀
最近感觉框架上非常弱鸡,于是找到了EventBus,想通过解析源码,学习架构设计最后并手写实现EventBus框架。
那么,gogogo 先从源码查看出发,一步一步实现自己的EventBus吧;
路漫漫其修远兮
01. 手写EventBus框架——源码分析1
02. 手写EventBus框架——源码分析2
03. 手写EventBus框架——动手_整体架构设计
04. 手写EventBus框架——动手_终结
1. 订阅、取消订阅
EventBus3.0 使用方式如下:
public class SampleComponent extends Fragment
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}
@Subscribe
public void gogogo(param)
{
}
@Override
public void onDestroy()
{
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
1.1 注册
1.1.1 注册源码分析
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map
以上就是 register 所做的事情;
-
subscriberMethodFinder.findSubscriberMethods(subscriberClass)
找到所有 EventBus 匹配的方法; - 循环逐个调用缓存订阅方法
subscribe
,最终缓存进入subscriptionsByEventType
和typesBySubscriber
;
看一下如何找到匹配方法列表的;
*** SubscriberMethodFinder.class ***
private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//使用反射查找。
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 使用Info取出方法 默认该方法
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 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);
}
以上可以看出 本质都是调用 findUsingReflection
*** SubscriberMethodFinder.class ***
private List findUsingReflection(Class> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
//这里的 clazz == subscriberClass;
while (findState.clazz != null) {
//找到只有一个参数的 方法集合;
findUsingReflectionInSingleClass(findState);
//转移到 父 Clazz
findState.moveToSuperclass();
}
//这里 就是返回 findState.subscriberMethods;
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 找到所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// 找到 public方法,包含继承和接口的方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
//判断修饰符, Public 不包含 static, abstaact
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
//判断方法数为 1
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)) {
//抛异常
}
}
}
这一段可以看出它的实现机制:核心原理是反射。
亮点:其中判断标识符的方式 与Android源码非常类似;
int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
//判断修饰符, Public 不包含 static, abstaact
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0)
{
//...
}
1.1.2 小结——注册事件分析
注册的源码已经分析过了,来个小小的总结
流程:
- 先找到所有 方法数量为1个且带有
@Subscribe
注解的方法 - 将方法寄存进我们的缓存当中(
subscriptionsByEventType
和typesBySubscriber
和stickyEvents
)
其它收获
-
CopyOnWriteArrayList
线程读写安全的列表 -
ConcurrentHashMap
支持检索的完全并发性的哈希表 - 存储的一个设计,非常巧妙。
1.2 取消注册
比较简单。缓存清除
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
// 移除
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
2. 发布
我们平常调用时这样的
EventBus.getDefault().post(param);
//或者
EventBus.getDefault().postSticky(param);
o.O
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
public void post(Object event) {
//...
}
本质都是调用 post 方法;
2.2 post (Object event)
让我们来瞧瞧 它是什么鬼
private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
public void post(Object event) {
//获取当前线程 的 PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
List
这边可以看到 先会从 currentPostingThreadState 取出状态,各种判断 然后调用postSingleEvent
。
postSingleEvent
这可是块硬骨头;
再难也要啃下它,哼哼...
2.3 postSingleEvent()
private static final Map, List>> eventTypesCache = new HashMap<>();
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//
//...
// 进入
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
//...
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
//...
//如果没有执行,第一次会进入以下方法
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
// 包装成 NoSubscriberEvent 方法
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
//获取 subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//...
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
//...
}
}
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);
}
}
2.3.1 小结——Post事件分析
** 流程**
- 根据EventType 得到subscriptions = subscriptionsByEventType 中的CopyOnWriteArrayList
; - 循环 subscriptions,并调用
postToSubscription
发送 ; -
postToSubscription
内根据线程类型来执行方法; - 发布了以后 缓存方法直接执行。
使用注意点:
从这边的分析可以看出来,post调用以后,会直接执行订阅方法,那么订阅方(Activity)不在栈顶的时候,如果做些动画展示,那是很耗性能的,那就尴尬了。。
这边梳理了整个事件的流程与原理,顺带也收获到了一些干货
细节方面没有那么深入。
下一篇: 02. 手写EventBus框架——源码分析2
希望我的文章不会误导在观看的你,如果有异议的地方欢迎讨论和指正。
如果能给观看的你带来收获,那就是最好不过了。