带你从源码解析EventBus
2017-03-03 15:39
477 查看
1EventBus的使用
1.1如何注册
1.2普及几个名词
1.3如何使用
2源码分析
3方法的权限符
第一种方式:推荐
EventBus.getDefault().register(this);//第一种方式获取EventBus对象
这种方式是通过系统的方式单例获取一个EventBus对象
第二种方式:不推荐
//第二种方式获取EventBus对象,这种不推荐,因为如果要是
用的话得自己去维护这个EventBus对象。不方便,因为消息的发送必须是一个EventBus对象
//将当前的MainActivity作为一个订阅者
EventBus.getDefault().register(this);
这就是将当前的MainActivity作为一个订阅者,(x消息接受者),subscribe
Subscriber:事件订阅者,用于接收事件
onEvent:发送者在哪个线程发送的,该方法也在哪个线程中处理事件
onEventMainThread:不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventBackgroundThread:如果发送者是在子线程发送的,那么该方法也在同一个子线程处理事件,如果发送者是在主线程,那么该方法在一个线程池中处理事件
onEventAsync:不管发送者在哪个线程发送的,该方法都在线程池中执行
为了验证这个我们分别在主线程和子线程发送消息,看下四个回调方法的执行情况
下面是SecondActivity主线程发送消息的log
我们可以看出 onEvent:ThreadName=main,因为发送者在哪个线程发送的,该方法也在哪个线程中处理事件
onEventMainThread:ThreadName=main因为不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventAsync:ThreadName=pool-1-thread-1,因为不管发送者在哪个线程发送的,该方法都在线程池中执行
下面是子线程发送消息的log
onEvent:ThreadName=Thread-70,因为发送者在哪个线程发送的,该方法也在哪个线程中处理事件,发送消息的线程编号是70
onEventBackgroundThread:ThreadName=Thread-70,如果发送者是在子线程发送的,那么该方法也在同一个子线程处理事件,如果发送者是在主线程,那么该方法在一个线程池中处理事件
onEventMainThread:ThreadName=main因为不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventAsync:ThreadName=pool-1-thread-3因为不管发送者在哪个线程发送的,该方法都在线程池中执行EventBus,一般在不用的时候要反注册一下,在ondestroy里,也可以根据实际情况自己去取消注册。
譬如activity给service发送消息,只需要service的Oncreate方法中注册下,如果想仅仅让service接收到其他的接受不到给参数类换个唯一的就可以了
打印的log
上面仅仅是知道怎么去使用,而我们的脚步肯定不仅仅限于此。
让我们从源码看EventBus都做了什么可以实现activity,service,广播间的通信
看源码切记第一眼要看一个类的构造。
EventBus构造函数
下面看下findSubscribeerMethods方法做了什么,其实就是通过订阅者的字节码拿到类中方法,进而调用
下面看subscribe做了什么操作
下面我们看post做了什么?
可以看出这个是根据Subscription不同的线程模型调用不同的方法。
1.1如何注册
1.2普及几个名词
1.3如何使用
2源码分析
3方法的权限符
EventBus的使用
//注册订阅者如何注册
//如何获取EventBus对象第一种方式:推荐
EventBus.getDefault().register(this);//第一种方式获取EventBus对象
这种方式是通过系统的方式单例获取一个EventBus对象
public static EventBus getDefault() { if(defaultInstance == null) { Class var0 = EventBus.class; synchronized(EventBus.class) { if(defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
第二种方式:不推荐
EventBus build = EventBus.builder().build();
//第二种方式获取EventBus对象,这种不推荐,因为如果要是
用的话得自己去维护这个EventBus对象。不方便,因为消息的发送必须是一个EventBus对象
//将当前的MainActivity作为一个订阅者
EventBus.getDefault().register(this);
这就是将当前的MainActivity作为一个订阅者,(x消息接受者),subscribe
普及几个名词
先给大家普及几个名词Subscriber:事件订阅者,用于接收事件
onEvent:发送者在哪个线程发送的,该方法也在哪个线程中处理事件
onEventMainThread:不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventBackgroundThread:如果发送者是在子线程发送的,那么该方法也在同一个子线程处理事件,如果发送者是在主线程,那么该方法在一个线程池中处理事件
onEventAsync:不管发送者在哪个线程发送的,该方法都在线程池中执行
为了验证这个我们分别在主线程和子线程发送消息,看下四个回调方法的执行情况
下面是SecondActivity主线程发送消息的log
11-01 10:15:10.580 1065-1065/com.example.zew.eventbusdemo E/MainActivity: onEvent:ThreadName=main接受到了消息:com.example.zew.eventbusdemo.MyEvent1@ade61ae0 11-01 10:15:10.580 1065-1139/com.example.zew.eventbusdemo E/MainActivity: onEventAsync:ThreadName=pool-1-thread-1接受到了消息:com.example.zew.eventbusdemo.MyEvent1@ade61ae0 11-01 10:15:10.590 1065-1065/com.example.zew.eventbusdemo E/MainActivity: onEventMainThread:ThreadName=main接受到了消息:com.example.zew.eventbusdemo.MyEvent1@ade61ae0 11-01 10:15:10.590 1065-1140/com.example.zew.eventbusdemo E/MainActivity: onEventBackgroundThread:ThreadName=pool-1-thread-2接受到了消息:com.example.zew.eventbusdemo.MyEvent1@ade61ae0
我们可以看出 onEvent:ThreadName=main,因为发送者在哪个线程发送的,该方法也在哪个线程中处理事件
onEventMainThread:ThreadName=main因为不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventAsync:ThreadName=pool-1-thread-1,因为不管发送者在哪个线程发送的,该方法都在线程池中执行
下面是子线程发送消息的log
11-01 10:19:12.490 1065-2656/com.example.zew.eventbusdemo E/MainActivity: onEvent:ThreadName=Thread-70接受到了消息:com.example.zew.eventbusdemo.MyEvent1@adea0b58 11-01 10:19:12.490 1065-2656/com.example.zew.eventbusdemo E/MainActivity: onEventBackgroundThread:ThreadName=Thread-70接受到了消息:com.example.zew.eventbusdemo.MyEvent1@adea0b58 11-01 10:19:12.500 1065-1065/com.example.zew.eventbusdemo E/MainActivity: onEventMainThread:ThreadName=main接受到了消息:com.example.zew.eventbusdemo.MyEvent1@adea0b58 11-01 10:19:12.500 1065-2657/com.example.zew.eventbusdemo E/MainActivity: onEventAsync:ThreadName=pool-1-thread-3接受到了消息:com.example.zew.eventbusdemo.MyEvent1@adea0b58
onEvent:ThreadName=Thread-70,因为发送者在哪个线程发送的,该方法也在哪个线程中处理事件,发送消息的线程编号是70
onEventBackgroundThread:ThreadName=Thread-70,如果发送者是在子线程发送的,那么该方法也在同一个子线程处理事件,如果发送者是在主线程,那么该方法在一个线程池中处理事件
onEventMainThread:ThreadName=main因为不管发送者在哪个线程发送的,该方法都会在主线程中处理事件
onEventAsync:ThreadName=pool-1-thread-3因为不管发送者在哪个线程发送的,该方法都在线程池中执行EventBus,一般在不用的时候要反注册一下,在ondestroy里,也可以根据实际情况自己去取消注册。
如何使用
其实EventBus也可以实现不同组件之间的通信譬如activity给service发送消息,只需要service的Oncreate方法中注册下,如果想仅仅让service接收到其他的接受不到给参数类换个唯一的就可以了
btnJumpSecAct.setOnClickListener(this); sendMsg2Service.setOnClickListener(this); EventBus.getDefault().register(this); startService(new Intent(this,Myservice.class)); } @Override public void onClick(View v) { if (v.getId()==R.id.btn_jumpSecAct){ startActivity(new Intent(this,SecondAct.class)); }else if (v.getId()==R.id.btn_service){ //给Myservice发送消息 EventBus.getDefault().post(new MyserviceEvent1("MainActivity给Myservice发送的消息",3)); } } 在service中 @Override public void onCreate() { //注册订阅者,subscribe EventBus.getDefault().register(this); super.onCreate(); } //声明用于事件处理的回调函数,注意权限修饰符必须为public,形参:声明一个接受的消息模型。这里我用的是MyEvent1类的对象 public void onEvent(MyserviceEvent1 event){ Log.e(TAG,"service接收到了消息"+event.msg); }
打印的log
11-06 07:09:22.840 9147-9147/com.example.zew.eventbusdemo E/Myservice: service接收到了消息MainActivity给Myservice发送的消息
上面仅仅是知道怎么去使用,而我们的脚步肯定不仅仅限于此。
让我们从源码看EventBus都做了什么可以实现activity,service,广播间的通信
源码分析
注册:regeister:看源码切记第一眼要看一个类的构造。
EventBus构造函数
EventBus(EventBusBuilder builder) { this.currentPostingThreadState = new ThreadLocal() { protected EventBus.PostingThreadState initialValue() { return new EventBus.PostingThreadState(); } }; this.subscriptionsByEventType = new HashMap(); this.typesBySubscriber = new HashMap(); this.stickyEvents = new ConcurrentHashMap(); this.mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); this.backgroundPoster = new BackgroundPoster(this); this.asyncPoster = new AsyncPoster(this); this.subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses); this.logSubscriberExceptions = builder.logSubscriberExceptions; this.logNoSubscriberMessages = builder.logNoSubscriberMessages; this.sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; this.sendNoSubscriberEvent = builder.sendNoSubscriberEvent; this.throwSubscriberException = builder.throwSubscriberException; this.eventInheritance = builder.eventInheritance; this.executorService = builder.executorService; }
private synchronized void register(Object subscriber, boolean sticky, int priority) { List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); Iterator i$ = subscriberMethods.iterator();//遍历当前订阅者的所有订阅方法 while(i$.hasNext()) { SubscriberMethod subscriberMethod = (SubscriberMethod)i$.next(); this.subscribe(subscriber, subscriberMethod, sticky, priority);遍历封装的订阅方法 } }
下面看下findSubscribeerMethods方法做了什么,其实就是通过订阅者的字节码拿到类中方法,进而调用
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {//传进去一个订阅者字节码 String key = subscriberClass.getName();//字节码名称作为键值对,值就是订阅方法onEventXX方法,这样做是为了缓存 Map clazz = methodCache; List subscriberMethods; synchronized(methodCache) { subscriberMethods = (List)methodCache.get(key);//这里是做了一次同步,因为map不支持的并发 } if(subscriberMethods != null) { return subscriberMethods;//如果有缓存,直接返回订阅方法集合 } else { ArrayList var23 = new ArrayList(); Class var24 = subscriberClass;//获取订阅者的字节码 HashSet eventTypesFound = new HashSet(); for(StringBuilder methodKeyBuilder = new StringBuilder(); var24 != null; var24 = var24.getSuperclass()) { String name = var24.getName(); if(name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { break; } Method[] methods = var24.getDeclaredMethods();//暴力反射 Method[] arr$ = methods; int len$ = methods.length;//这里我们拿到字节码里的所有的方法名,然后遍历获取到我们订阅的方法 for(int i$ = 0; i$ < len$; ++i$) { Method method = arr$[i$]; String methodName = method.getName(); if(methodName.startsWith("onEvent")) {//筛选onEvent开头的方法 int modifiers = method.getModifiers();//获取方法的权限修饰符 if((modifiers & 1) != 0 && (modifiers & 5192) == 0) {//必须是public Class[] parameterTypes = method.getParameterTypes();//这里通过方法拿到方法的形式参数字节码类型的数组 if(parameterTypes.length == 1) {//如果形式参数个数为1,一般我们形式参数就是一个 String modifierString = methodName.substring(“onEvent”.length());//截取后的字符串 ThreadMode threadMode;//线程模型,下面几行代码就是通过截取后的字符串确定对应的线程模型 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")) { if(!this.skipMethodVerificationForClasses.containsKey(var24)) { throw new EventBusException("Illegal onEvent method, check for typos: " + method); } continue; } threadMode = ThreadMode.Async; } Class eventType = parameterTypes[0];//方法的第一个形参类型字节码 methodKeyBuilder.setLength(0); methodKeyBuilder.append(methodName); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); if(eventTypesFound.add(methodKey)) {//然后通过把方法名,方法形参,线程模型封装成一个SubscriberMethod添加进集合里 var23.add(new SubscriberMethod(method, threadMode, eventType)); } } } else if(!this.skipMethodVerificationForClasses.containsKey(var24)) { Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + var24 + "." + methodName); } } } } if(var23.isEmpty()) {//如果拿到你的OnEvent的订阅放大为空,直接给你抛个异常 throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " + "onEvent"); } else { Map var25 = methodCache; synchronized(methodCache) { methodCache.put(key, var23);//如果不为空就给你放倒一个缓存里,因为每次都反射是耗时费资源的,所以缓存下 return var23; } } } }
下面看subscribe做了什么操作
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) { Class eventType = subscriberMethod.eventType;//通过拿到订阅方法参数的字节码 CopyOnWriteArrayList subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);//通过参数的字节码从subscriptionsByEventType集合中获取到订阅者 Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority); if(subscriptions == null) {//如果为空,就创建一个将当前的订阅者添加到subscriptionsByEventType中,其实就是初始化subscriptionsByEventType,第一次进来都是为null subscriptions = new CopyOnWriteArrayList(); this.subscriptionsByEventType.put(eventType, subscriptions); } else if(subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } int size = subscriptions.size(); for(int subscribedEvents = 0; subscribedEvents <= size; ++subscribedEvents) { if(subscribedEvents == size || newSubscription.priority > ((Subscription)subscriptions.get(subscribedEvents)).priority) { subscriptions.add(subscribedEvents, newSubscription);//根据订阅者的优先级添加到subscriptions中,优先级高的在前面 break; } } Object var14 = (List)this.typesBySubscriber.get(subscriber);//通过这个订阅者获取到订阅者对应的事件类型 if(var14 == null) {//如果为空 var14 = new ArrayList(); this.typesBySubscriber.put(subscriber, var14);//那就讲这个订阅者和和其所有的订阅的事件类型添加到这个构造方法就创建的typesBySubscriber Map中 } ((List)var14).add(eventType); if(sticky) { Map var11 = this.stickyEvents; Object stickyEvent; synchronized(this.stickyEvents) { stickyEvent = this.stickyEvents.get(eventType); } if(stickyEvent != null) { this.postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper()); } } }
下面我们看post做了什么?
public void post(Object event) { " EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();//currentPostingThreadState就是ThreadLocal类。他就是绑定当前线程的一个类,通过这个get肯定是从当前线程绑定的类中拿东西。 " List eventQueue = postingState.eventQueue;//通过当前线程的获取到当前线程的队列queue。 eventQueue.add(event);//将event添加到队列里面。 if(!postingState.isPosting) {//判断当前线程是否已经在分发事件 postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();//判断执行post的线程是否是主线程 postingState.isPosting = true; if(postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while(!eventQueue.isEmpty()) {//遍历EventQueue,调用postSingleEvent this.postSingleEvent(eventQueue.remove(0), postingState);//从头部开始取 } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } } private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error { Class eventClass = event.getClass();//拿到当前事件字节码 boolean subscriptionFound = false; if(this.eventInheritance) {//判断是否支持继承//默认是支持继承的,可以修改 List eventTypes = this.lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for(int h = 0; h < countTypes; ++h) { Class clazz = (Class)eventTypes.get(h); subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass); } //由上面方法可以看出支持父类的话得不停的遍历调用postSingleEventForEventType而不支持的话只需要调用一次postSingleEventForEventType,节省性能,所以我们可以对EventBus做一次封装让其不支持父类 if(!subscriptionFound) {//如果为空的话就会发送一个NoSubscriberEvent结束掉了 if(this.logNoSubscriberMessages) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if(this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { this.post(new NoSubscriberEvent(this, event)); } } }
private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {//获取到事件的父类和接口的字节码到集合中 Map var2 = eventTypesCache; synchronized(eventTypesCache) { Object eventTypes = (List)eventTypesCache.get(eventClass); if(eventTypes == null) { eventTypes = new ArrayList(); for(Class clazz = eventClass; clazz != null; clazz = clazz.getSuperclass()) { ((List)eventTypes).add(clazz); addInterfaces((List)eventTypes, clazz.getInterfaces()); } eventTypesCache.put(eventClass, eventTypes); } return (List)eventTypes; } }
private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList subscriptions; synchronized(this) { subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass); }//通过该事件字节码获取所有的订阅者。 if(subscriptions != null && !subscriptions.isEmpty()) {//如果订阅者为空返回false Iterator i$ = subscriptions.iterator(); while(i$.hasNext()) {//不为空遍历subscriptions分别调用postToSubscription Subscription subscription = (Subscription)i$.next(); postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { this.postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if(aborted) { break; } } return true; } else { return false; } }
可以看出这个是根据Subscription不同的线程模型调用不同的方法。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch(EventBus.SyntheticClass_1.$SwitchMap$de$greenrobot$event$ThreadMode[subscription.subscriberMethod.threadMode.ordinal()]) { case 1: this.invokeSubscriber(subscription, event); break; case 2: if(isMainThread) { this.invokeSubscriber(subscription, event); } else { this.mainThreadPoster.enqueue(subscription, event);//其实是handler发送消息 } break; case 3: if(isMainThread) { this.backgroundPoster.enqueue(subscription, event);//在线程池总发送消息 } else { this.invokeSubscriber(subscription, event); } break; case 4: this.asyncPoster.enqueue(subscription, event);//在线程池发送消息 break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
void invokeSubscriber(Subscription subscription, Object event) { try {//通过反射调用订阅者订阅方法 subscription.subscriberMethod.method.invoke(subscription.subscriber, new Object[]{event}); } catch (InvocationTargetException var4) { this.handleSubscriberException(subscription, event, var4.getCause()); } catch (IllegalAccessException var5) { throw new IllegalStateException("Unexpected exception", var5); } }
方法的权限符
PUBLIC: 1 (二进制 0000 0001) PRIVATE: 2 (二进制 0000 0010) PROTECTED: 4 (二进制 0000 0100) STATIC: 8 (二进制 0000 1000) FINAL: 16 (二进制 0001 0000) SYNCHRONIZED: 32 (二进制 0010 0000) VOLATILE: 64 (二进制 0100 0000) TRANSIENT: 128 (二进制 1000 0000) NATIVE: 256 (二进制 0001 0000 0000) INTERFACE: 512 (二进制 0010 0000 0000) ABSTRACT: 1024 (二进制 0100 0000 0000) STRICT: 2048 (二进制 1000 0000 0000)
相关文章推荐
- EventBus 利弊与源码解析
- 开源项目源码解析-EventBus 源码解析
- [EventBus源码解析] EventBus.register 方法详述
- Android EventBus源码解析
- [EventBus源码解析] 订阅者处理消息的四种ThreadMode
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- EventBus源码解析
- EventBus 源码解析
- EventBus(2)——源码解析
- EventBus 源码解析
- Android EventBus源码解析 带你深入理解EventBus
- EventBus 源码解析
- [EventBus源码解析] 初探EventBus
- Android EventBus源码解析 带你深入理解EventBus
- EventBus源码解析 带你深入理解EventBus
- EventBus---EventBus源码解析 带你深入理解EventBus
- EventBus 源码解析(一)
- Android EventBus源码解析 带你深入理解EventBus
- Android 源码解析:EventBus