本篇主要介绍eventbus的使用以及源码分析
####Eventbus是什么
- 专门为Android设计的用于订阅,发布总线的库
- andorid组件之间通信
- 。。。
现有的通信方式
同一进程线程间:
- handler
- 共享静态变量
- eventbus
进程间:
- aidl
- socket
- 广播
- contentProvider
- Messager
以上aidl跟广播也可以在同一个进程中使用,但一般同一个进程通信的话不太会用到
####为什么使用eventbus
相比于handler,handler通信是单向的,没有handler的线程可以向有handler的一方发消息。常见的是子线程d可以给主线程发消息(子线程做完耗时操作之后通知主线程修改ui)。如果主线程要给子线程发消息的话,需要子线程new looper,实现handler,并让主线程持有该handler,推荐直接使用HandlerThread(包含looper的thread)。相对来说代码量不小。
共享静态变量这种方法耗内存不推荐。
eventBus中子线程传递消息给主线程实质使用的还是handler,但是它比使用handler的方式简单很多。下面会给出详细分析。
使用方法
- 定义一个pojo:message的实体类
- 注册接受消息的类并在在该类中定义接收消息的方法
- 发送消息
- 合适的地方取消注册
示例:
实体类:
1 | package com.example.kj_eventbus; |
接收消息的类:
1 | public class MainActivity extends AppCompatActivity { |
发送消息:
1 | public class SendMsgAct extends AppCompatActivity { |
源码解析
注解的使用
1 |
|
- 该注解运行时生效,用于注解方法,标示接收消息的线程,消息的优先级,以及是否是粘性的消息
- 利用该注解可以在运行时通过反射获取到(类—方法—MessageType)对应的关系;
- 具体代码后面会给出分析
初始化
这里使用了单例跟建造者模式构建evenbus实例。但是为什么构造函数是public的呢?有知道的同学可以告我一哈~
1 | //单例 |
注册类
1 | public void register(Object subscriber) { |
该方法是注册入口,主要两步:
- 首先通过findSubscriberMethods找到该类的SubscirberMethod(接收消息的方法的封装)集合;
- 之后调用subscribe初始化subscriptionsByEventType(通过messageType找到subsciption)typesBySubscriber(通过注册类找到MessageType)
下面我们先跟踪下findSubscriberMethods:
1 | List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { |
该方法先从cache中获取,之后通过apt或者反射获取。我们先分析反射(默认),也就是findUsingInfo()
1 | private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { |
之后进入findUsingReflectionInSingleClass
1 | private void findUsingReflectionInSingleClass(FindState findState) { |
之后会调用getMethodsAndRelease;
1 | private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { |
最终返回的是该注册类中接收消息的方法集合。
接着我们进入第二步,subscribe:
1 | private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { |
以上,regist分析完毕。
发送消息
1 | public void post(Object event) { |
其中的isMainThread()要从mainThreadSupport的初始化说起:
点击进入isMainThread()
1 | private boolean isMainThread() { |
可见是根据mainThreadSupport来判断的,接着我们找到mainThreadSupport初始化的地方
1 | EventBus(EventBusBuilder builder) { |
进入getMainThreadSupport
1 | MainThreadSupport getMainThreadSupport() { |
我们看下Logger.AndroidLogger.isAndroidLogAvailable()
1 | public static class AndroidLogger implements Logger { |
返回的是ANDROID_LOG_AVAILABLE,这个值如果存在“android.util.Log”,那么为true,否则为false,意思就是如果是运行在android中,那么为true,否则为false;
接着我们看下getAndroidMainLooperOrNull();
1 | Object getAndroidMainLooperOrNull() { |
返回的是主线程的looper,一定不为空,
那么getMainThreadSupport的返回值就是 MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull)
接着我们看下AndroidHandlerMainThreadSupport
1 | class AndroidHandlerMainThreadSupport implements MainThreadSupport { |
其实就是把AndroidHandlerMainThreadSupport中的looper初始化为主线程的looper。
此时我们在看isMainThread()。如果Looper.myLooper返回的跟主线程的looper一致,那么自然就是主线程了。因为列子中是在子线程中发的消息,所以此时返回false。我们回到post方法中:
postingState的成员变量eventQueue中有我们发送的消息,isMainThread=false;
接着只要eventQueue不为空,就执行postSingleEvent(eventQueue.remove(0), postingState);
1 | private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { |
那么接着我们进入lookupAllEventTypes
1 | private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { |
就是返回MessageType以及它的父类的List
返回之后接着执行postSingleEventForEventType(event, postingState, clazz)
1 | private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { |
这里通过subscriptionsByEventType找到该MessageType对应的subscriptions,将它赋给postingState.subscription,将该MessageType赋给postingState.event,之后调用postToSubscription(subscription, event, postingState.isMainThread);
1 | private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { |
例子中threadMode是Main,发送消息是在子线程中,接下来会执行mainThreadPoster.enqueue(subscription, event)
这里就要从mainThreadPoster的初始化说起(Eventbus构造方法中):
1 | mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null; |
mainThreadSupport.createPoster(this)
1 | class AndroidHandlerMainThreadSupport implements MainThreadSupport { |
我们上面提到过这里的looper是主线程的looper。我们接着进入new HandlerPoster(eventBus, looper, 10)
1 | public class HandlerPoster extends Handler implements Poster { |
HandlerPoster是EventBus中比较重要的类,它继承自handler,因为我们传入的looper是主线程的,所以该handler是主线程的handler。
此时回到我们的初衷:mainThreadPoster.enqueue(subscription, event);
这里会将subscription跟event转化为PendingPost,pendingpost是用来做消息复用的,具体如下:
1 | static PendingPost obtainPendingPost(Subscription subscription, Object event) { |
核心思路就是如果pendingPostPool这个池子里有,那么就从池子里拿,没有才会new 对象。拿到PendingPost之后,将它放入PendingPostQueue队列中。之后执行sendMessage(obtainMessage())发送一个空消息。
接着我们进入handleMessage。改方法会从PendingPostQueue队列中不断的poll数据,知道队列为空。每个数据都会执行eventBus.invokeSubscriber(pendingPost);
1 | void invokeSubscriber(PendingPost pendingPost) { |
改方法就是通过反射调用接收消息的方法。
以上,完成了子线程给主线程传递消息的整个过程。
如果接收消息也是子线程(也就是threadMode设置的是backGround),如果发送消息在主线程,那么会调用backgroundPoster.enqueue(subscription, event);将线程切换到子线程中,否者直接反射调用即可。最后我们看下backgroundPoster的实现:
1 | final class BackgroundPoster implements Runnable, Poster { |
它本身是一个runnable,维护着一个队列,入队列之后执行eventBus.getExecutorService().execute(this)把自己放入线程池中(cache线程池),此时就会执行run方法,而run方法会不断的从队列中poll数据,之后反射执行。
反射优化:apt
运行时使用反射对会有一定的性能损耗,使用apt(注解工具)通过编译时生成对应的代码,从而规避了运行时反射。
总结
实质:当发送某个消息时执行特定类的特定方法
原理:其实就是利用注解跟反射通过注册类的方式将(类—方法–消息类型)对应的关系表维护在Eventbus中,当post某个消息时查询该关系表,通过反射执行指定类的指定方法,切换线程使用handler跟线程池。
最后:evenbus中相关的知识点有很多:设计模式,线程池,handler,ThreadLocal,反射,注解,多线程…源码还是推荐大家简单看一下。