- 浏览: 56655 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (218)
- ★★★ Android ★★★ (37)
- 【 Java 基础】✚ (0)
- ☞Java 基础概述 (0)
- ☞Java 基本语法 (0)
- ☞Java 面向对象编程 (0)
- ☞Java多线程 (0)
- ☞Java 异常处理 (0)
- ☞Java 集合框架 (0)
- ☞Java 泛型 (0)
- ☞Java 枚举和注解 (0)
- ☞Java IO流 (0)
- ☞Java 常用类 (0)
- ☞Java GUI键盘事件 (0)
- ☞Java 网络编程 (0)
- ☞Java 正则表达式 (0)
- ☞Java 反射机制 (0)
- ☞Java 小项目 (0)
- ☞Java 面试/笔试题 (0)
- 【HTML5 开发基础】✚ (0)
- ☞HTML常用标签 (0)
- ☞HTML 新特性 (0)
- ☞CSS/CSS3常用语法 (0)
- ☞JavaScript基础语法 (0)
- ☞HTML5 小项目 (0)
- ☞HTML5 面试/笔试题 (0)
- 【Android 基础阶段】✚ (12)
- ☞Android 快速入门 (1)
- ☞Android 核心组件 (1)
- ☞Android Intent (0)
- ☞Android 用户界面 (5)
- ☞Android 数据存储 (0)
- ☞Android Tomcat服务器 (0)
- ☞Android 网络编程 (2)
- ☞Android 消息机制 (0)
- ☞Android 事件机制 (0)
- ☞Fragment和ViewPager (3)
- ☞Android动画与图形处理 (0)
- ☞Android多媒体应用开发 (1)
- ☞Android 传感器开发等 (0)
- ☞Android GPS应用 (0)
- ☞Android C语言 (0)
- ☞Android JNI/NDK开发 (0)
- ☞Android Git/SVN (0)
- ☞Android 小项目 (0)
- ☞Android 面试/笔试题 (0)
- 【Android 微知识点】✚ (7)
- ☞Android 一些模版代码 (0)
- ☞Android 模块功能代码 (0)
- ☞Android UI控件大全 (2)
- ☞Android 自定义适配器 (1)
- ☞Android 自定义属性 (3)
- ☞Android 自定义动画 (0)
- ☞Android 启动过程 (0)
- ☞Android 性能优化 (0)
- ☞Android 图片三级缓存 (0)
- ☞Android 屏幕适配 (0)
- ☞Android OOM内存溢出 (0)
- ☞Android 权限 (0)
- ☞Android JNI (0)
- 【Android 网络编程】✚ (1)
- ☞Android Json解析 (2)
- ☞Android 网络请求 (2)
- 【Android 解析器】✚ (0)
- ☞Android XML (0)
- ☞Android DOM (0)
- ☞Android dom4j (0)
- ● (0)
- ●● (0)
- ●●● (0)
- ●●●● (0)
- ●●●●● (0)
- ●●●●●● (0)
- ●●●●●●● (0)
- ●●●●●●●● (0)
- ●●●●●●●●● (0)
- ☞☞☞☞☞☞☞☞☞☞ (0)
- ☞☞☞☞☞☞☞☞☞ (0)
- ☞☞☞☞☞☞☞☞ (0)
- ☞☞☞☞☞☞☞ (0)
- ☞☞☞☞☞☞ (0)
- ☞☞☞☞☞ (0)
- ☞☞☞☞ (0)
- ☞☞☞ (0)
- ☞☞ (0)
- ☞ (0)
- 【Android重量级框架】✚ (14)
- ☞框架归类 (1)
- ☞Gson (0)
- ☞xUtils3 (2)
- ☞xListView (0)
- ★ Volley (0)
- ★ AndroidAnnotations (0)
- ★ Glide (0)
- ★ SlidingMenu (0)
- ★ TabLayout (1)
- ★ ViewPagerIndicator (4)
- ★ Pulltorefresh (1)
- ★ PhotoView (1)
- ★ EventBus (0)
- ★ Vitamio5.0 (0)
- ★ Image-Loader (1)
- ★ Android-gif-drawable (0)
- ★ ActionBar (0)
- ★ ActionBarSherlock (0)
- ★ OkHttp (0)
- ★ Afinal (2)
- ★ Ffmpeg (0)
- ★ RxJava (0)
- ★ Picasso (0)
- ★ FastJson (0)
- ★ Toolbar (0)
- ★ GreenDao (0)
- ★ Otto (0)
- ★ ORMLite (0)
- ★ Retrofit (0)
- ★ Fresco (0)
- ★ SnappyDB (0)
- ★ Butterknife (0)
- ★ PagerSlidingTabStrip (0)
- PinterestLikeAdapterView (0)
- ★ NotBoringActionBar (0)
- ★ StickyListHeaders (0)
- ★ NineOldAndroids (0)
- ★ Expandablelistview (0)
- ★ SwipeRefreshLayout (0)
- ★ SwipeMenuListView (0)
- ★ (0)
- ★★ (0)
- ★★★ (0)
- ★★★★ (0)
- ★★★★★ (0)
- ★★★★★★ (0)
- ★★★★★★★ (0)
- ★★★★★★★★ (0)
- ★★★★★★★★★ (0)
- ★★★★★★★★★★ (0)
- ❉❉❉❉❉❉❉❉❉❉ (0)
- ❉❉❉❉❉❉❉❉❉ (0)
- ❉❉❉❉❉❉❉❉ (0)
- ❉❉❉❉❉❉❉ (0)
- ❉❉❉❉❉❉ (0)
- ❉❉❉❉❉ (0)
- ❉❉❉❉ (0)
- ❉❉❉ (0)
- ❉❉ (0)
- ❉ (0)
- 【第三方分享库】✚ (0)
- ○○○○○○○○○○ (0)
- ○○○○○○○○○ (0)
- ○○○○○○○○ (0)
- ○○○○○○○ (0)
- ○○○○○○ (0)
- ○○○○○ (0)
- ○○○○ (0)
- ○○○ (0)
- ○○ (0)
- ○ (1)
- 【Android开源项目】✚ (1)
- ☞综合性项目 (0)
- ☞多媒体项目 (1)
- ☞新闻性项目 (2)
- ☞社交性项目 (0)
- ☞商城性项目 (0)
- ☞Android 支付宝 (0)
- ☞Android 第三方登录 (0)
- ☞Android 语音识别 (0)
- ☞Android消息推送 (1)
- ☞Android 蓝牙 (0)
- ☞Android 传感器 (0)
- ☞Android 动画 (0)
- ☞Android 省市县三级联动 (0)
- ☞短信验证技术 (0)
- ☞二维码扫描技术 (0)
- ☂ (0)
- ☂☂ (0)
- ☂☂☂ (0)
- ☂☂☂☂ (0)
- ☂☂☂☂☂ (0)
- ☂☂☂☂☂☂ (0)
- ☂☂☂☂☂☂☂ (0)
- ☂☂☂☂☂☂☂☂ (0)
- ☂☂☂☂☂☂☂☂☂ (0)
- ☂☂☂☂☂☂☂☂☂☂ (0)
- ♣♣♣♣♣♣♣♣♣♣ (0)
- ♣♣♣♣♣♣♣♣♣ (0)
- ♣♣♣♣♣♣♣♣ (0)
- ♣♣♣♣♣♣♣ (0)
- ♣♣♣♣♣♣ (0)
- ♣♣♣♣♣ (0)
- ♣♣♣♣ (0)
- ♣♣♣ (0)
- ♣♣ (0)
- ♣ (0)
- 【Android源码分析】✚ (4)
- 【Android项目阶段】✚ (1)
- ☞Android主流架构搭建 (0)
- ☞综合性<手机安全卫士> (0)
- ☞多媒体<手机影音> (1)
- ☞新闻性<北京新闻> (0)
- ☞社交性<硅谷社交> (0)
- ☞商城性<硅谷商城> (0)
- ☞内涵段子<百思> (0)
- ☞<地图相关开发接口> (0)
- ☞下载<电子应用市场> (0)
- ☞智能<手机遥控家电> (0)
- ☞游戏<植物大战僵尸> (0)
- ☞企业实战<开源中国> (0)
- ☞Android5.0+6.0新特性 (0)
- ☞高级特效专辑 (0)
- ☞项目管理与实施 (0)
- ☞项目经验:面试/笔试题 (0)
- 【Android 前沿技术】✚ (0)
- ☞图文混排技术 (0)
- ☞百分比布局 (0)
- H5混合开发☞ (0)
- ☞APP增量升级 (0)
- ☞软件崩溃收集 (0)
- ☞前沿技术分享 (0)
- 【Android+H5混合开发】✚ (0)
- ☞React基本语法 (0)
- ☞React Native开发环境搭建 (0)
- ☞React Native开发基础 (0)
- ☞React Native常用组件 (0)
- ☞React Native常用API (0)
- ☞豆瓣搜索项目 (0)
- ☏ (0)
- ☏☏ (0)
- ☏☏☏ (0)
- ☏☏☏☏ (0)
- ☏☏☏☏☏ (0)
- ☏☏☏☏☏☏ (0)
- ☏☏☏☏☏☏☏ (0)
- ☏☏☏☏☏☏☏☏ (0)
- ☏☏☏☏☏☏☏☏☏ (0)
- ☏☏☏☏☏☏☏☏☏☏ (0)
- ☎☎☎☎☎☎☎☎☎☎ (0)
- ☎☎☎☎☎☎☎☎☎ (0)
- ☎☎☎☎☎☎☎☎ (0)
- ☎☎☎☎☎☎☎ (0)
- ☎☎☎☎☎☎ (0)
- ☎☎☎☎☎ (0)
- ☎☎☎ (0)
- ☎☎ (0)
- ☎ (0)
- 【Android+H5项目实战】✚ (0)
- 【程序员软件系列】✚ (4)
- ☞Eclipse (0)
- ☞Android Studio (4)
- ☞Genymotion (0)
- ☞Tomcat服务器 (0)
- ☞MyScal (0)
- ☀ (0)
- ☀☀ (0)
- ☀☀☀ (0)
- ☀☀☀☀ (0)
- ☀☀☀☀☀ (0)
- ☀☀☀☀☀☀ (0)
- ☀☀☀☀☀☀☀ (0)
- ☀☀☀☀☀☀☀☀ (0)
- ☀☀☀☀☀☀☀☀☀ (0)
- ☀☀☀☀☀☀☀☀☀☀ (0)
- ☻☻☻☻☻☻☻☻☻☻ (0)
- ☻☻☻☻☻☻☻☻☻ (0)
- ☻☻☻☻☻☻☻☻ (0)
- ☻☻☻☻☻☻☻ (0)
- ☻☻☻☻☻☻ (0)
- ☻☻☻☻☻ (0)
- ☻☻☻☻ (0)
- ☻☻☻ (0)
- ☻☻ (0)
- ☻ (0)
- ♬♬♬ 技术网站 ♬♬♬ (2)
- ◙ (0)
- ◙◙ (0)
- ◙◙◙ (0)
- ◙◙◙◙ (0)
- ◙◙◙◙◙ (0)
- ◘◘◘◘◘ (0)
- ◘◘◘◘ (0)
- ◘◘◘ (0)
- ◘◘ (0)
- ◘ (0)
- 【Android 其他技术】✚ (0)
- ☞Android反编译 (0)
- ☞抓包 (0)
- ☞多渠道打包及软件上线 (0)
- 【github项目/博客系列】✚ (1)
- ☞注册github步骤 (0)
- ☞github项目 (0)
- ☞优秀博客系列 (1)
- 【开发经验分享】✚ (2)
- ☞Android 知识体系 (1)
- ☞项目经验分享 (0)
- ☞面试与就业指导 (1)
- ☞Android面试技术汇总 (2)
- ♬♬♬ 词汇 ♬♬♬ (0)
- 【Android基础单词】✚ (0)
- 【javaSE单词】✚ (0)
- 【个人博客资料】✚ (0)
- 博客链接 (1)
- 快速开发 (1)
- JavaEE面试题 (1)
最新评论
EventBus---EventBus源码解析 带你深入理解EventBus
转载自:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:【张鸿洋的博客】
上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢?
1、概述
一般使用EventBus的组件类,类似下面这种方式:
- publicclassSampleComponentextendsFragment
- {
- @Override
- publicvoidonCreate(BundlesavedInstanceState)
- {
- super.onCreate(savedInstanceState);
- EventBus.getDefault().register(this);
- }
- publicvoidonEventMainThread(param)
- {
- }
- publicvoidonEventPostThread(param)
- {
- }
- publicvoidonEventBackgroundThread(param)
- {
- }
- publicvoidonEventAsync(param)
- {
- }
- @Override
- publicvoidonDestroy()
- {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
- }
- <spanstyle="font-size:14px;">publicclassSampleComponentextendsFragment
- {
- @Override
- publicvoidonCreate(BundlesavedInstanceState)
- {
- super.onCreate(savedInstanceState);
- EventBus.getDefault().register(this);
- }
- publicvoidonEventMainThread(param)
- {
- }
- publicvoidonEventPostThread(param)
- {
- }
- publicvoidonEventBackgroundThread(param)
- {
- }
- publicvoidonEventAsync(param)
- {
- }
- @Override
- publicvoidonDestroy()
- {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
- }</span>
大多情况下,都会在onCreate中进行register,在onDestory中进行unregister ;
看完代码大家或许会有一些疑问:
1、代码中还有一些以onEvent开头的方法,这些方法是干嘛的呢?
在回答这个问题之前,我有一个问题,你咋不问register(this)是干嘛的呢?其实register(this)就是去当前类,遍历所有的方法,找到onEvent开头的然后进行存储。现在知道onEvent开头的方法是干嘛的了吧。
2、那onEvent后面的那些MainThread应该是什么标志吧?
嗯,是的,onEvent后面可以写四种,也就是上面出现的四个方法,决定了当前的方法最终在什么线程运行,怎么运行,可以参考上一篇博客或者细细往下看。
既然register了,那么肯定得说怎么调用是吧。
- EventBus.getDefault().post(param);
- <spanstyle="font-size:14px;">EventBus.getDefault().post(param);</span>
调用很简单,一句话,你也可以叫发布,只要把这个param发布出去,EventBus会在它内部存储的方法中,进行扫描,找到参数匹配的,就使用反射进行调用。
现在有没有觉得,撇开专业术语:其实EventBus就是在内部存储了一堆onEvent开头的方法,然后post的时候,根据post传入的参数,去找到匹配的方法,反射调用之。
那么,我告诉你,它内部使用了Map进行存储,键就是参数的Class类型。知道是这个类型,那么你觉得根据post传入的参数进行查找还是个事么?
下面我们就去看看EventBus的register和post真面目。
2、register
EventBus.getDefault().register(this);
首先:
EventBus.getDefault()其实就是个单例,和我们传统的getInstance一个意思:
- /**Conveniencesingletonforappsusingaprocess-wideEventBusinstance.*/
- publicstaticEventBusgetDefault(){
- if(defaultInstance==null){
- synchronized(EventBus.class){
- if(defaultInstance==null){
- defaultInstance=newEventBus();
- }
- }
- }
- returndefaultInstance;
- }
- <spanstyle="font-size:14px;">/**Conveniencesingletonforappsusingaprocess-wideEventBusinstance.*/
- publicstaticEventBusgetDefault(){
- if(defaultInstance==null){
- synchronized(EventBus.class){
- if(defaultInstance==null){
- defaultInstance=newEventBus();
- }
- }
- }
- returndefaultInstance;
- }</span>
使用了双重判断的方式,防止并发的问题,还能极大的提高效率。
然后register应该是一个普通的方法,我们去看看:
register公布给我们使用的有4个:
- publicvoidregister(Objectsubscriber){
- register(subscriber,DEFAULT_METHOD_NAME,false,0);
- }
- publicvoidregister(Objectsubscriber,intpriority){
- register(subscriber,DEFAULT_METHOD_NAME,false,priority);
- }
- publicvoidregisterSticky(Objectsubscriber){
- register(subscriber,DEFAULT_METHOD_NAME,true,0);
- }
- publicvoidregisterSticky(Objectsubscriber,intpriority){
- register(subscriber,DEFAULT_METHOD_NAME,true,priority);
- }
- <spanstyle="font-size:14px;">publicvoidregister(Objectsubscriber){
- register(subscriber,DEFAULT_METHOD_NAME,false,0);
- }
- publicvoidregister(Objectsubscriber,intpriority){
- register(subscriber,DEFAULT_METHOD_NAME,false,priority);
- }
- publicvoidregisterSticky(Objectsubscriber){
- register(subscriber,DEFAULT_METHOD_NAME,true,0);
- }
- publicvoidregisterSticky(Objectsubscriber,intpriority){
- register(subscriber,DEFAULT_METHOD_NAME,true,priority);
- }</span>
本质上就调用了同一个:
- privatesynchronizedvoidregister(Objectsubscriber,StringmethodName,booleansticky,intpriority){
- List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
- methodName);
- for(SubscriberMethodsubscriberMethod:subscriberMethods){
- subscribe(subscriber,subscriberMethod,sticky,priority);
- }
- }
- <spanstyle="font-size:14px;">privatesynchronizedvoidregister(Objectsubscriber,StringmethodName,booleansticky,intpriority){
- List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
- methodName);
- for(SubscriberMethodsubscriberMethod:subscriberMethods){
- subscribe(subscriber,subscriberMethod,sticky,priority);
- }
- }</span>
四个参数
subscriber是我们扫描类的对象,也就是我们代码中常见的this;
methodName 这个是写死的:“onEvent”,用于确定扫描什么开头的方法,可见我们的类中都是以这个开头。
sticky 这个参数,解释源码的时候解释,暂时不用管
priority 优先级,优先级越高,在调用的时候会越先调用。
下面开始看代码:
- List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
- methodName);
- <spanstyle="font-size:14px;">List<SubscriberMethod>subscriberMethods=subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),
- methodName);</span>
调用内部类SubscriberMethodFinder的findSubscriberMethods方法,传入了subscriber 的class,以及methodName,返回一个List<SubscriberMethod>。
那么不用说,肯定是去遍历该类内部所有方法,然后根据methodName去匹配,匹配成功的封装成SubscriberMethod,最后返回一个List。下面看代码:
- List<SubscriberMethod>findSubscriberMethods(Class<?>subscriberClass,StringeventMethodName){
- Stringkey=subscriberClass.getName()+'.'+eventMethodName;
- List<SubscriberMethod>subscriberMethods;
- synchronized(methodCache){
- subscriberMethods=methodCache.get(key);
- }
- if(subscriberMethods!=null){
- returnsubscriberMethods;
- }
- subscriberMethods=newArrayList<SubscriberMethod>();
- Class<?>clazz=subscriberClass;
- HashSet<String>eventTypesFound=newHashSet<String>();
- StringBuildermethodKeyBuilder=newStringBuilder();
- while(clazz!=null){
- Stringname=clazz.getName();
- if(name.startsWith("java.")||name.startsWith("javax.")||name.startsWith("android.")){
- //Skipsystemclasses,thisjustdegradesperformance
- break;
- }
- //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
- Method[]methods=clazz.getMethods();
- for(Methodmethod:methods){
- StringmethodName=method.getName();
- if(methodName.startsWith(eventMethodName)){
- intmodifiers=method.getModifiers();
- if((modifiers&Modifier.PUBLIC)!=0&&(modifiers&MODIFIERS_IGNORE)==0){
- Class<?>[]parameterTypes=method.getParameterTypes();
- if(parameterTypes.length==1){
- StringmodifierString=methodName.substring(eventMethodName.length());
- ThreadModethreadMode;
- if(modifierString.length()==0){
- threadMode=ThreadMode.PostThread;
- }elseif(modifierString.equals("MainThread")){
- threadMode=ThreadMode.MainThread;
- }elseif(modifierString.equals("BackgroundThread")){
- threadMode=ThreadMode.BackgroundThread;
- }elseif(modifierString.equals("Async")){
- threadMode=ThreadMode.Async;
- }else{
- if(skipMethodVerificationForClasses.containsKey(clazz)){
- continue;
- }else{
- thrownewEventBusException("IllegalonEventmethod,checkfortypos:"+method);
- }
- }
- Class<?>eventType=parameterTypes[0];
- methodKeyBuilder.setLength(0);
- methodKeyBuilder.append(methodName);
- methodKeyBuilder.append('>').append(eventType.getName());
- StringmethodKey=methodKeyBuilder.toString();
- if(eventTypesFound.add(methodKey)){
- //Onlyaddifnotalreadyfoundinasubclass
- subscriberMethods.add(newSubscriberMethod(method,threadMode,eventType));
- }
- }
- }elseif(!skipMethodVerificationForClasses.containsKey(clazz)){
- Log.d(EventBus.TAG,"Skippingmethod(notpublic,staticorabstract):"+clazz+"."
- +methodName);
- }
- }
- }
- clazz=clazz.getSuperclass();
- }
- if(subscriberMethods.isEmpty()){
- thrownewEventBusException("Subscriber"+subscriberClass+"hasnopublicmethodscalled"
- +eventMethodName);
- }else{
- synchronized(methodCache){
- methodCache.put(key,subscriberMethods);
- }
- returnsubscriberMethods;
- }
- }
- <spanstyle="font-size:14px;">List<SubscriberMethod>findSubscriberMethods(Class<?>subscriberClass,StringeventMethodName){
- Stringkey=subscriberClass.getName()+'.'+eventMethodName;
- List<SubscriberMethod>subscriberMethods;
- synchronized(methodCache){
- subscriberMethods=methodCache.get(key);
- }
- if(subscriberMethods!=null){
- returnsubscriberMethods;
- }
- subscriberMethods=newArrayList<SubscriberMethod>();
- Class<?>clazz=subscriberClass;
- HashSet<String>eventTypesFound=newHashSet<String>();
- StringBuildermethodKeyBuilder=newStringBuilder();
- while(clazz!=null){
- Stringname=clazz.getName();
- if(name.startsWith("java.")||name.startsWith("javax.")||name.startsWith("android.")){
- //Skipsystemclasses,thisjustdegradesperformance
- break;
- }
- //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
- Method[]methods=clazz.getMethods();
- for(Methodmethod:methods){
- StringmethodName=method.getName();
- if(methodName.startsWith(eventMethodName)){
- intmodifiers=method.getModifiers();
- if((modifiers&Modifier.PUBLIC)!=0&&(modifiers&MODIFIERS_IGNORE)==0){
- Class<?>[]parameterTypes=method.getParameterTypes();
- if(parameterTypes.length==1){
- StringmodifierString=methodName.substring(eventMethodName.length());
- ThreadModethreadMode;
- if(modifierString.length()==0){
- threadMode=ThreadMode.PostThread;
- }elseif(modifierString.equals("MainThread")){
- threadMode=ThreadMode.MainThread;
- }elseif(modifierString.equals("BackgroundThread")){
- threadMode=ThreadMode.BackgroundThread;
- }elseif(modifierString.equals("Async")){
- threadMode=ThreadMode.Async;
- }else{
- if(skipMethodVerificationForClasses.containsKey(clazz)){
- continue;
- }else{
- thrownewEventBusException("IllegalonEventmethod,checkfortypos:"+method);
- }
- }
- Class<?>eventType=parameterTypes[0];
- methodKeyBuilder.setLength(0);
- methodKeyBuilder.append(methodName);
- methodKeyBuilder.append('>').append(eventType.getName());
- StringmethodKey=methodKeyBuilder.toString();
- if(eventTypesFound.add(methodKey)){
- //Onlyaddifnotalreadyfoundinasubclass
- subscriberMethods.add(newSubscriberMethod(method,threadMode,eventType));
- }
- }
- }elseif(!skipMethodVerificationForClasses.containsKey(clazz)){
- Log.d(EventBus.TAG,"Skippingmethod(notpublic,staticorabstract):"+clazz+"."
- +methodName);
- }
- }
- }
- clazz=clazz.getSuperclass();
- }
- if(subscriberMethods.isEmpty()){
- thrownewEventBusException("Subscriber"+subscriberClass+"hasnopublicmethodscalled"
- +eventMethodName);
- }else{
- synchronized(methodCache){
- methodCache.put(key,subscriberMethods);
- }
- returnsubscriberMethods;
- }
- }</span>
呵,代码还真长;不过我们直接看核心部分:
22行:看到没,clazz.getMethods();去得到所有的方法:
23-62行:就开始遍历每一个方法了,去匹配封装了。
25-29行:分别判断了是否以onEvent开头,是否是public且非static和abstract方法,是否是一个参数。如果都复合,才进入封装的部分。
32-45行:也比较简单,根据方法的后缀,来确定threadMode,threadMode是个枚举类型:就四种情况。
最后在54行:将method, threadMode, eventType传入构造了:new SubscriberMethod(method, threadMode, eventType)。添加到List,最终放回。
注意下63行:clazz = clazz.getSuperclass();可以看到,会扫描所有的父类,不仅仅是当前类。
继续回到register:
- for(SubscriberMethodsubscriberMethod:subscriberMethods){
- subscribe(subscriber,subscriberMethod,sticky,priority);
- }
- <spanstyle="font-size:14px;">for(SubscriberMethodsubscriberMethod:subscriberMethods){
- subscribe(subscriber,subscriberMethod,sticky,priority);
- }</span>
for循环扫描到的方法,然后去调用suscribe方法。
- //Mustbecalledinsynchronizedblock
- privatevoidsubscribe(Objectsubscriber,SubscriberMethodsubscriberMethod,booleansticky,intpriority){
- subscribed=true;
- Class<?>eventType=subscriberMethod.eventType;
- CopyOnWriteArrayList<Subscription>subscriptions=subscriptionsByEventType.get(eventType);
- SubscriptionnewSubscription=newSubscription(subscriber,subscriberMethod,priority);
- if(subscriptions==null){
- subscriptions=newCopyOnWriteArrayList<Subscription>();
- subscriptionsByEventType.put(eventType,subscriptions);
- }else{
- for(Subscriptionsubscription:subscriptions){
- if(subscription.equals(newSubscription)){
- thrownewEventBusException("Subscriber"+subscriber.getClass()+"alreadyregisteredtoevent"
- +eventType);
- }
- }
- }
- //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
- //subscriberMethod.method.setAccessible(true);
- intsize=subscriptions.size();
- for(inti=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=newArrayList<Class<?>>();
- typesBySubscriber.put(subscriber,subscribedEvents);
- }
- subscribedEvents.add(eventType);
- if(sticky){
- ObjectstickyEvent;
- synchronized(stickyEvents){
- stickyEvent=stickyEvents.get(eventType);
- }
- if(stickyEvent!=null){
- //Ifthesubscriberistryingtoaborttheevent,itwillfail(eventisnottrackedinpostingstate)
- //-->Strangecornercase,whichwedon'ttakecareofhere.
- postToSubscription(newSubscription,stickyEvent,Looper.getMainLooper()==Looper.myLooper());
- }
- }
- }
- <spanstyle="font-size:14px;">//Mustbecalledinsynchronizedblock
- privatevoidsubscribe(Objectsubscriber,SubscriberMethodsubscriberMethod,booleansticky,intpriority){
- subscribed=true;
- Class<?>eventType=subscriberMethod.eventType;
- CopyOnWriteArrayList<Subscription>subscriptions=subscriptionsByEventType.get(eventType);
- SubscriptionnewSubscription=newSubscription(subscriber,subscriberMethod,priority);
- if(subscriptions==null){
- subscriptions=newCopyOnWriteArrayList<Subscription>();
- subscriptionsByEventType.put(eventType,subscriptions);
- }else{
- for(Subscriptionsubscription:subscriptions){
- if(subscription.equals(newSubscription)){
- thrownewEventBusException("Subscriber"+subscriber.getClass()+"alreadyregisteredtoevent"
- +eventType);
- }
- }
- }
- //StartingwithEventBus2.2weenforcedmethodstobepublic(mightchangewithannotationsagain)
- //subscriberMethod.method.setAccessible(true);
- intsize=subscriptions.size();
- for(inti=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=newArrayList<Class<?>>();
- typesBySubscriber.put(subscriber,subscribedEvents);
- }
- subscribedEvents.add(eventType);
- if(sticky){
- ObjectstickyEvent;
- synchronized(stickyEvents){
- stickyEvent=stickyEvents.get(eventType);
- }
- if(stickyEvent!=null){
- //Ifthesubscriberistryingtoaborttheevent,itwillfail(eventisnottrackedinpostingstate)
- //-->Strangecornercase,whichwedon'ttakecareofhere.
- postToSubscription(newSubscription,stickyEvent,Looper.getMainLooper()==Looper.myLooper());
- }
- }
- }</span>
我们的subscriberMethod中保存了method, threadMode, eventType,上面已经说了;
4-17行:根据subscriberMethod.eventType,去subscriptionsByEventType去查找一个CopyOnWriteArrayList<Subscription> ,如果没有则创建。
顺便把我们的传入的参数封装成了一个:Subscription(subscriber, subscriberMethod, priority);
这里的subscriptionsByEventType是个Map,key:eventType ; value:CopyOnWriteArrayList<Subscription> ;这个Map其实就是EventBus存储方法的地方,一定要记住!
22-28行:实际上,就是添加newSubscription;并且是按照优先级添加的。可以看到,优先级越高,会插到在当前List的前面。
30-35行:根据subscriber存储它所有的eventType ; 依然是map;key:subscriber ,value:List<eventType> ;知道就行,非核心代码,主要用于isRegister的判断。
37-47行:判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数。
postToSubscription这个方法,我们在post的时候会介绍。
到此,我们register就介绍完了。
你只要记得一件事:扫描了所有的方法,把匹配的方法最终保存在subscriptionsByEventType(Map,key:eventType ; value:CopyOnWriteArrayList<Subscription>)中;
eventType是我们方法参数的Class,Subscription中则保存着subscriber, subscriberMethod(method, threadMode, eventType), priority;包含了执行改方法所需的一切。
3、post
register完毕,知道了EventBus如何存储我们的方法了,下面看看post它又是如何调用我们的方法的。
再看源码之前,我们猜测下:register时,把方法存在subscriptionsByEventType;那么post肯定会去subscriptionsByEventType去取方法,然后调用。
下面看源码:
- /**Poststhegiveneventtotheeventbus.*/
- publicvoidpost(Objectevent){
- PostingThreadStatepostingState=currentPostingThreadState.get();
- List<Object>eventQueue=postingState.eventQueue;
- eventQueue.add(event);
- if(postingState.isPosting){
- return;
- }else{
- postingState.isMainThread=Looper.getMainLooper()==Looper.myLooper();
- postingState.isPosting=true;
- if(postingState.canceled){
- thrownewEventBusException("Internalerror.Abortstatewasnotreset");
- }
- try{
- while(!eventQueue.isEmpty()){
- postSingleEvent(eventQueue.remove(0),postingState);
- }
- }finally{
- postingState.isPosting=false;
- postingState.isMainThread=false;
- }
- }
- }
- <spanstyle="font-size:14px;">/**Poststhegiveneventtotheeventbus.*/
- publicvoidpost(Objectevent){
- PostingThreadStatepostingState=currentPostingThreadState.get();
- List<Object>eventQueue=postingState.eventQueue;
- eventQueue.add(event);
- if(postingState.isPosting){
- return;
- }else{
- postingState.isMainThread=Looper.getMainLooper()==Looper.myLooper();
- postingState.isPosting=true;
- if(postingState.canceled){
- thrownewEventBusException("Internalerror.Abortstatewasnotreset");
- }
- try{
- while(!eventQueue.isEmpty()){
- postSingleEvent(eventQueue.remove(0),postingState);
- }
- }finally{
- postingState.isPosting=false;
- postingState.isMainThread=false;
- }
- }
- }</span>
currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。
- privatefinalThreadLocal<PostingThreadState>currentPostingThreadState=newThreadLocal<PostingThreadState>(){
- @Override
- protectedPostingThreadStateinitialValue(){
- returnnewPostingThreadState();
- }
- }
- <spanstyle="font-size:14px;">privatefinalThreadLocal<PostingThreadState>currentPostingThreadState=newThreadLocal<PostingThreadState>(){
- @Override
- protectedPostingThreadStateinitialValue(){
- returnnewPostingThreadState();
- }
- }</span>
把我们传入的event,保存到了当前线程中的一个变量PostingThreadState的eventQueue中。
10行:判断当前是否是UI线程。
16-18行:遍历队列中的所有的event,调用postSingleEvent(eventQueue.remove(0), postingState)方法。
这里大家会不会有疑问,每次post都会去调用整个队列么,那么不会造成方法多次调用么?
可以看到第7-8行,有个判断,就是防止该问题的,isPosting=true了,就不会往下走了。
下面看postSingleEvent
- privatevoidpostSingleEvent(Objectevent,PostingThreadStatepostingState)throwsError{
- Class<?extendsObject>eventClass=event.getClass();
- List<Class<?>>eventTypes=findEventTypes(eventClass);
- booleansubscriptionFound=false;
- intcountTypes=eventTypes.size();
- for(inth=0;h<countTypes;h++){
- Class<?>clazz=eventTypes.get(h);
- CopyOnWriteArrayList<Subscription>subscriptions;
- synchronized(this){
- subscriptions=subscriptionsByEventType.get(clazz);
- }
- if(subscriptions!=null&&!subscriptions.isEmpty()){
- for(Subscriptionsubscription:subscriptions){
- postingState.event=event;
- postingState.subscription=subscription;
- booleanaborted=false;
- try{
- postToSubscription(subscription,event,postingState.isMainThread);
- aborted=postingState.canceled;
- }finally{
- postingState.event=null;
- postingState.subscription=null;
- postingState.canceled=false;
- }
- if(aborted){
- break;
- }
- }
- subscriptionFound=true;
- }
- }
- if(!subscriptionFound){
- Log.d(TAG,"Nosubscribersregisteredforevent"+eventClass);
- if(eventClass!=NoSubscriberEvent.class&&eventClass!=SubscriberExceptionEvent.class){
- post(newNoSubscriberEvent(this,event));
- }
- }
- }
- <spanstyle="font-size:14px;">privatevoidpostSingleEvent(Objectevent,PostingThreadStatepostingState)throwsError{
- Class<?extendsObject>eventClass=event.getClass();
- List<Class<?>>eventTypes=findEventTypes(eventClass);
- booleansubscriptionFound=false;
- intcountTypes=eventTypes.size();
- for(inth=0;h<countTypes;h++){
- Class<?>clazz=eventTypes.get(h);
- CopyOnWriteArrayList<Subscription>subscriptions;
- synchronized(this){
- subscriptions=subscriptionsByEventType.get(clazz);
- }
- if(subscriptions!=null&&!subscriptions.isEmpty()){
- for(Subscriptionsubscription:subscriptions){
- postingState.event=event;
- postingState.subscription=subscription;
- booleanaborted=false;
- try{
- postToSubscription(subscription,event,postingState.isMainThread);
- aborted=postingState.canceled;
- }finally{
- postingState.event=null;
- postingState.subscription=null;
- postingState.canceled=false;
- }
- if(aborted){
- break;
- }
- }
- subscriptionFound=true;
- }
- }
- if(!subscriptionFound){
- Log.d(TAG,"Nosubscribersregisteredforevent"+eventClass);
- if(eventClass!=NoSubscriberEvent.class&&eventClass!=SubscriberExceptionEvent.class){
- post(newNoSubscriberEvent(this,event));
- }
- }
- }</span>
将我们的event,即post传入的实参;以及postingState传入到postSingleEvent中。
2-3行:根据event的Class,去得到一个List<Class<?>>;其实就是得到event当前对象的Class,以及父类和接口的Class类型;主要用于匹配,比如你传入Dog extends Dog,他会把Animal也装到该List中。
6-31行:遍历所有的Class,到subscriptionsByEventType去查找subscriptions;哈哈,熟不熟悉,还记得我们register里面把方法存哪了不?
是不是就是这个Map;
12-30行:遍历每个subscription,依次去调用postToSubscription(subscription, event, postingState.isMainThread);
这个方法就是去反射执行方法了,大家还记得在register,if(sticky)时,也会去执行这个方法。
下面看它如何反射执行:
- privatevoidpostToSubscription(Subscriptionsubscription,Objectevent,booleanisMainThread){
- switch(subscription.subscriberMethod.threadMode){
- casePostThread:
- invokeSubscriber(subscription,event);
- break;
- caseMainThread:
- if(isMainThread){
- invokeSubscriber(subscription,event);
- }else{
- mainThreadPoster.enqueue(subscription,event);
- }
- break;
- caseBackgroundThread:
- if(isMainThread){
- backgroundPoster.enqueue(subscription,event);
- }else{
- invokeSubscriber(subscription,event);
- }
- break;
- caseAsync:
- asyncPoster.enqueue(subscription,event);
- break;
- default:
- thrownewIllegalStateException("Unknownthreadmode:"+subscription.subscriberMethod.threadMode);
- }
- }
- <spanstyle="font-size:14px;">privatevoidpostToSubscription(Subscriptionsubscription,Objectevent,booleanisMainThread){
- switch(subscription.subscriberMethod.threadMode){
- casePostThread:
- invokeSubscriber(subscription,event);
- break;
- caseMainThread:
- if(isMainThread){
- invokeSubscriber(subscription,event);
- }else{
- mainThreadPoster.enqueue(subscription,event);
- }
- break;
- caseBackgroundThread:
- if(isMainThread){
- backgroundPoster.enqueue(subscription,event);
- }else{
- invokeSubscriber(subscription,event);
- }
- break;
- caseAsync:
- asyncPoster.enqueue(subscription,event);
- break;
- default:
- thrownewIllegalStateException("Unknownthreadmode:"+subscription.subscriberMethod.threadMode);
- }
- }
- </span>
前面已经说过subscription包含了所有执行需要的东西,大致有:subscriber, subscriberMethod(method, threadMode, eventType), priority;
那么这个方法:第一步根据threadMode去判断应该在哪个线程去执行该方法;
case PostThread:
- voidinvokeSubscriber(Subscriptionsubscription,Objectevent)throwsError{
- subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
- }
- <spanstyle="font-size:14px;">voidinvokeSubscriber(Subscriptionsubscription,Objectevent)throwsError{
- subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
- }
- </span>
直接反射调用;也就是说在当前的线程直接调用该方法;
case MainThread:
首先去判断当前如果是UI线程,则直接调用;否则:mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。
case BackgroundThread:
如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用
executorService = Executors.newCachedThreadPool();。
case Async:将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。
这么说BackgroundThread和Async有什么区别呢?
BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。
Async则会动态控制并发。
到此,我们完整的源码分析就结束了,总结一下:register会把当前类中匹配的方法,存入一个map,而post会根据实参去map查找进行反射调用。分析这么久,一句话就说完了~~
其实不用发布者,订阅者,事件,总线这几个词或许更好理解,以后大家问了EventBus,可以说,就是在一个单例内部维持着一个map对象存储了一堆的方法;post无非就是根据参数去查找方法,进行反射调用。
4、其余方法
介绍了register和post;大家获取还能想到一个词sticky,在register中,如何sticky为true,会去stickyEvents去查找事件,然后立即去post;
那么这个stickyEvents何时进行保存事件呢?
其实evevntbus中,除了post发布事件,还有一个方法也可以:
- publicvoidpostSticky(Objectevent){
- synchronized(stickyEvents){
- stickyEvents.put(event.getClass(),event);
- }
- //Shouldbepostedafteritisputted,incasethesubscriberwantstoremoveimmediately
- post(event);
- }
- <spanstyle="font-size:14px;">publicvoidpostSticky(Objectevent){
- synchronized(stickyEvents){
- stickyEvents.put(event.getClass(),event);
- }
- //Shouldbepostedafteritisputted,incasethesubscriberwantstoremoveimmediately
- post(event);
- }</span>
和post功能类似,但是会把方法存储到stickyEvents中去;
大家再去看看EventBus中所有的public方法,无非都是一些状态判断,获取事件,移除事件的方法;没什么好介绍的,基本见名知意。
好了,到此我们的源码解析就结束了,希望大家不仅能够了解这些优秀框架的内部机理,更能够体会到这些框架的很多细节之处,并发的处理,很多地方,为什么它这么做等等。
相关推荐
eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载;eventbus-3.0.0 jar包及源代码下载
EventBus 是一个流行于 Android 开发中的发布/订阅事件总线库,由 ...在 "eventbus-3.0.0.jar+eventbus-3.0.0-sources.jar" 中,你将获得 EventBus 最新版本的功能和源码,有助于深入理解和使用这个强大的工具。
android eventbus-3.2.0.jar 解压就可以使用
"eventbus-3.1.1.jar" 文件是 EventBus 的一个特定版本,版本号为 3.1.1,通常包含该库的 Java 类和资源,用于集成到 Android 项目中。 在 EventBus 中,事件(Event)是通过发布(Posting)和订阅(Subscribing)...
在`EventBus-master`这个压缩包中,包含了Go-EventBus的源代码和示例。首先,我们需要导入库: ```go import "github.com/gocraft/event" ``` 然后,创建一个事件总线实例: ```go bus := event.New() ``` 接...
在 "eventbus-3.0.0.jar" 文件中,包含了 EventBus 的这个特定版本的所有类和资源,使得开发者可以在项目中方便地引入和使用 EventBus。 1. **事件总线概念**:EventBus 是一种设计模式,它将事件发布者和事件订阅...
总的来说,EventBus-2.1.0-beta-1.jar 是一个强大的 Android 事件通信库,它通过简化组件间通信,提高了代码的可读性和可维护性。理解并熟练使用 EventBus,可以极大地提升 Android 应用的开发效率和质量。
"eventBus-3.1.1.jar"是EventBus库的一个特定版本,包含所有必要的类和资源,便于开发者将其集成到他们的项目中。 在Android开发中,通常我们需要在不同的组件(如Activity、Fragment或Service)之间传递信息。传统...
安卓 EventBus 使用示例,开发工具为eclipse+ADT,EventBus可简化安卓各个组件,线程之间的通信 相关博客 http://blog.csdn.net/qq_34763699/article/details/79467327
EventBus-master.zip项目安卓应用源码下载EventBus-master.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
【标题】"Weiz.EventBus-master.zip" 是一个与 .NET 框架相关的压缩包,其中包含了 Weiz.EventBus 的示例代码。这个库是一个事件总线(Event Bus)实现,用于在应用程序的不同组件之间传递事件,促进松耦合和更好的...
Android应用源码之EventBus-master.zip项目安卓应用源码下载Android应用源码之EventBus-master.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
本文将深入探讨 EventBus 的核心概念、工作原理以及如何在实际项目中应用。 ### 核心概念 1. **发布者(Publishers)**:发布者是事件的来源,当某个事件发生时,发布者会通过 EventBus 发布事件。发布者通常是...
compile 'com.shizhefei:eventbus-api:1.2.1' //eventbus 注解 compile 'com.shizhefei:eventbus-annotation:1.2.1' 在定义Event接口的Module添加,以便于生成Event接口的代理 annotationProcessor '...
EventBus-iOS是一个针对iOS...总的来说,EventBus-iOS提供了一种在iOS应用中实现事件驱动编程的有效方式,通过理解和运用这个框架,开发者可以更好地组织代码结构,减少组件间的耦合,提高系统的可维护性和可扩展性。
netflix-eventbus-0.3.0.jar
EventBus最新的jar包,2016-5-10
EventBus 是一个流行的 Android 事件总线库,它简化了应用程序内部组件之间的通信。相比于传统的回调或静态方法,EventBus 提供了一种订阅发布模式,使得组件之间可以通过发布事件来传递消息,而无需显式地调用接口...