以前试着看过Android其他源码, 后来感觉是一脸懵逼, 并且经常是只顾着把代码意思搞懂就以为完事, 然后没过多久就忘了, 这次看源码看了些资料, 发现如果能试着去理解作者的套路, 效果或许会好一些, 并且可能会学到点儿技巧.
EventBus源码其实挺简单, 类的数量也不多.
1.从一个小demo开始:
其实平时工作中用到最多的也就是这几个方法;
2.试着分析源码:
EventBut.getDefault().register(this);
作者使用的是volatile关键字创建的单例模式, 我可以把volatile提出来, 不是说我想说单例模式的正确写法, 而是顺便给自己提个醒, 现在volatile我也看的是一知半解, 等我把深入理解Java虚拟机看完, 我就开始看Java并发编程, 绝世好书啊, 这是我查资料看到volatile博客的感想, 这里不对volatile做总结, 总结不出来, 只贴一个链接:
http://www.cnblogs.com/dolphin0520/p/3920373.html
然后开始register(Object subscriber):
看源码时有一个小套路, 不一定从头到尾看, 有返回值时先从return下手, 返回值是subScriberMethods
List<SubScriberMethod> subScriberMethods = METHOD_CACHE.get(subScriberClass);
接下来从ignoreGeneratedIndex开始, 定位该变量发现, 他的默认值为false, 去官方文档查了一下, EventBus3.0之前使用的是findUserReflection();3.0之后使用的是findUsingInfo(); 至于为何, 后面把两个方法分析完再做总结.
接下来看findUsingReflection();
还是先从getMethodsAndRelease(findState)入手
这里其实也值得我们借鉴, 注意getMethodsAndRelease()与prepareFindState()这两个方法里面的FIND_STATE_POOL这个数组, 我看到有些地方说是为了防止并发, 但是貌似并发跟这个复用池的思想用时取出, 用完放回并没有什么关系, 他用的是synchronized保证的线程同步, ListArray的底层也是数组, 他直接操作数组, 先让数组每一为置为null, 然后不断的替换对应位置的null, 然后不断取出放回, 这些操作的时间复杂度都是O[1], 这样做的目的应该是这里, 降低时间复杂度.
然后切到initForSubscriber方法:
该方法仅仅是进行了赋值操作.
然后切入到findUsingReflectionInSingleClass()方法:
里面有几个地方需要关注一哈
1. getDeclaredMethods()与getMethods();
getDeclaredMethods()返回自身的方法, getMethods()返回包括父类中的public方法(不包括native方法)
2. 一系列方法说明EventBus的规定:
1、if(modifiers & Modifier.PUBLIC)!=0… ->对订阅方法格式做了要求, 只能是public
2、parameterTypes.length == 1 -> 方法的形参个数只能为1
我们之前返回的值为findState.subscriberMethods
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
集合一定要重点关注get和add方法, add出现在
if (findState.checkAdd(method, eventType)) {
SubscriberMethod subscriber;
subscriber = new SubscriberMethod(method,
eventType,
threadMode,
subscribeAnnotation.priority(),
subscribeAnnotation.sticky()));
findState.subscriberMethods.add(subscriber);
}
如果要保证程序正常执行, 就一定要保证checkAdd的返回值为true;
切入到checkAdd():
1、如果是第一次进入, 返回true
2、如果第二次进入, 切入到checkAddWithMethodSignature()方法:
a.isAssiginableFrom(b)//a与b相同或者是b的父类或者父接口,则返回true
暂时只发现该方法一定返回true, 不知道else{…}何时才会执行
然后我们回到findUsingReflectionInSingleClass方法
在平时使用过程中, 我们一般都是这样操作的
@Subscribe
public void onMessage(Object obj){...}
切入到Subscribe
1、threadMode默认为PISTING
2、ThreadMode类型:POSTING、MAIN、BACKGROUND、ASYNC
EventBus3.0之前的方法分析完了
接下来看看EventBus3.0之后的方法:
findUsingInfo():
然后在执行到getSubscriberInfo(findState)以后发现findState.subscribeInfo == null, 最终还是执行到else中, 查看文档才知道需要我们自己去配置,然后才会执行3.0以后这个新加的逻辑.
至此EventBus.getDefault().register(this)分析完了.
然后我们来分析EventBus.getDefault().post()方法:
采用ThreadLocal模式, 一个线程对应一个PostingThreadState; 他这种写法如果以后在工作中遇到, 我们就可以这样模仿一哈.
1、将event添加到消息队列中;
2、isPosting默认为false;
3、判断当前线程是否是主线程;
4、切入到postSingleEvent();
该方法中重点关注两个方法:
1、lookupAllEventTypes(eventClass);
2、subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
切入到 lookupAllEventTypes(eventClass);
方法如其名, 采用递归的方式将Event对象及其父类, 父接口添加到eventClass中;暂时可能会有疑惑, 不知道为何要讲父类父接口全部添加到eventClass中, 我们继续向后看, 没准就会有所收获.
1、最终利用反射调用目标方法;
2、如果定义ThreadModel.threadModel = MAIN, 但是我们在子线程直接调用post方法会发生什么现象呢?
threadModel = ThreadMode.POSTING:
threadModel = ThreadMode.MAIN:
这个源码当我们使用MAIN模式时, 在子线程进行post时, EventBus内部使用Handler模式帮我们把消息切换到主线程了.