EventBus
一、前言
(一)、作用
1、Android 事件发布 / 订阅框架
2、事件传递既可以用于Android 四大组件间的通信
3、用户异步线程和主线程间通信的时候进行联系的工具
(二)、意义
通过框架解耦事件的 发布者 和订阅者 ,进而简化Android 事件传递
(三)、优点
代码简洁,使用简单,并将事件发布和订阅充分解耦
(四)、传统的事件传递方法
a、handler
b、BroadcastReceiver
c、接口回调
传统事件传递的缺陷:
代码量臃肿、繁琐、复杂
传统事件传递之handler
handler 机制工作原理
ps:Android 中的主线程 :ActivityThread 类——Ui线程
通过这个类创建的Looper 和 Handler 就可以进行消息的传递了
思考1:子线程是否可以创建handler对象?
答: 子线程直接创建handler对象会报 缺少Looper对象的错误。进行三个步骤创建handler :
1、调用Looper的prepare()方法创建当前线程的Looper
2、之后创建当前线程的Handler()
3、在创建完Handler()后要通过Looper.loop()开启Looper消息队列的循环
解析:在Android异步消息处理机制中,handler就是用来处理消息的,并进行消息的发送,和处理在handleMessage。
发出、经过处理的消息最后都会回到handler这个方法中来执行。
Looper 每个线程中MessageQueue的管家,负责消息队列的运作。Looper内部死循环不断的从MessageQueue中获取消息,
有消息就取出并返回给handleMessage去进行处理。所以也就是说单单仅有一个handler是无法进行消息的处理工作的,因为没有Looper 无法获取MessageQueue 中的消息。
也就是说需要handler发送消息后通过Looper接收消息,放到MessageQueue中进行轮询操作。最后looper会将Message 返回给handler,调用handleMessage 方法进行异步消息的处理操作。
思考2:handler 在Activity中进行消息的传递有几种形式?
实例代码一 形式:
/**
* 利用handler,在Ui 主线程中发送消息,在work子线程执行耗时操作
*/
public class HandlerSendMessageActivity extends Activity {
public Button btn1;
Handler handler;//主线程handler
public TextView textview;
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.butterknife_layout);
textview = findViewById(R.id.textview_1);
btn1 = findViewById(R.id.button_1);
btn1.setText("Ui->Work");
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//主线程发送消息给子线程去处理需要耗时的操作
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
System.out.println(Thread.currentThread().getName());
}
});
new MyThread().start();
}
class MyThread extends Thread {
@Override
public void run() {
//子线程创建handler之前一定要首先创建looper 通过Looper.prepare();
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName());
super.handleMessage(msg);
}
};
Looper.loop();
super.run();
}
}
}
实例代码二 形式:
/**
* 利用handler,在子线程发送消息,然后在主线程中获取并执行
*/
public class HandlerGetMessageActivity extends Activity {
Button btn1;
//1、主线程定义handler 并重现handleMessage()
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName());
System.out.println("消息-->" + msg.arg1 + "-" + msg.obj);
super.handleMessage(msg);
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.butterknife_layout);
btn1 = findViewById(R.id.button_1);
btn1.setText("Work-->Ui");
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//2、开启一个子线程在run()方法中发送消息给主线程处理
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
System.out.println(Thread.currentThread().getName());
}
});
thread.start();
}
});
}
}
二、EventBus框架基本用法
(一)eventbus 流程图
event ———event————Subscriber
Publisher ——————>Event Bus — |
(发布器) post() ———event————Subscriber
流程:发布器 通过post()方法 把event 发布到 event bus 总线当中 ,eventbus总线中根据 event 事件类型 匹配给相应的订阅者
ps:注意只有注册了事件才能收到event 发送的请求;同时反注册可以清理需要的eventbus请求
(二)eventbus 使用方法
1、导入:
implementation ‘org.greenrobot:eventbus:3.0.0‘
2、定义自定义事件event类型
public class MyBusEvent{
public final String message;
public MyBusEvent(String message) {
this.message = message;
}
}
3、创建订阅者-通过注解
//订阅者一定要带上@Subscribe注解,eventbus之后的订阅者方法名可以随意
@Subscribe(定义这个方法完成的线程级别),不用考虑线程问题抛出的异常
@Subscribe(threadMode = ThreadMode.MAIN) //表示onMessageEvent()在主线程中完成
public void onMessageEvent(MyBusEvent event) {
System.out.println();
}
}
4、注册与反注册事件
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
ps:注册与反注册 如果在Activity 或是fragment 这类组件,尽量与它的生命周期绑定在一起
5、发送事件 -无位置限制-主/子线程均可以发送事件
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//主线程发送消息给子线程去处理需要耗时的操作
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
//将自定义的事件类型,作为参数传递给post()函数
EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
}
});
ps:所有注册、订阅这个事件的订阅者都能够匹配接收的这个事件xxx
三、EventBus框架的对象构建 和线程调度
EventBus 的实例化均带有EventBus.getDefault() 方法,所以以此为入口:
简单来说:EventBus就是一个单例模式创建并用构建者模式Build内部类构建的对象
EventBus.getDefault():双检查机制的单例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
思考:单例模式构造函数一般都是private修饰的,但是eventBus的构造模式是public 修饰的,这个原因是?
publicEventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
解析:EventBus在代码中并不是只有一条 总线,还有其他的总线。订阅者可以注册到不同的EventBus上,通过不同的EventBus发送数据。不同的EventBus发送的数据是相互隔离开的,订阅者只会收到注册在该线程上的数据。通过上面DEFAULT_BUILDER 对象的初始化可以发现EventBus构建对象是通过构建者模式 Builde内部类 进行构建的。
EventBus 的对象构建
private final ThreadLocal<PostingThreadState> currentPostingThreadState= new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
ps:ThreadLocal是 线程内部的数据存储类 ,通过它可以在指定的线程中存储数据,也只有在指定的线程中可以获取到数据。其他线程无法获取到
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
//以event 为key,以subscribe为value值
ps:可以通过subscriptionsByEventType这个HashMap找到对应的订阅者
typesBySubscriber = new HashMap<>();
//以subscribe为key,以event为value
ps:当进行注册和反注册事件的时候都会在这个typesBySubscriber HashMap中操作
stickyEvents = new ConcurrentHashMap<>();
//粘性事件,当event发送出去后再注册粘性事件的话,这个粘性事件也能收到之前发送的event事件
ps:ConcurrentHashMap是一个并发的HashMap
思考 :什么是post? 答: 负责线程间调度
三个比较重要的成员变量的初始化 mainThreadPoster、backgroundPoster、asyncPoster
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //eventbus生成的索引
//对已经设定好注解的@Subscribe的Method方法的找寻器
//通过这个方法找寻设定好注解的方法
subscriberMethodFinder= new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions; //发生异常是否进行异常信息的打印
logNoSubscriberMessages = builder.logNoSubscriberMessages;//没有订阅者订阅该事件的时候是否打印日志
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//当调用事件处理函数时若发生异常是否需要发送这个事件
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//当没有事件处理的时候是否对事件处理发送sendNoSubscriberEvent
throwSubscriberException = builder.throwSubscriberException;//是否需要抛出异常
eventInheritance = builder.eventInheritance; //与event有继承关系的是否都需要发送
executorService = builder.executorService;
}
下面看一下eventBus 最核心的三个线程间调度的方法:
(1) 、mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
final class HandlerPoster extends Handler所以可知其实际上就是个handler 具柄
//存放即将执行的post的队列
private final PendingPostQueue queue;
//post这个事件最大的所能在handler当中handleMessage()所存在的最大时间值 max值
private final int maxMillisInsideHandleMessage;
//标着者handler是否运行起来
private boolean handlerActive;
在handleMessage()方法的任务,首先开启while一个循环,从队列中不停的获取数据后,调用invokeSubscriber()方法进行事件的分发
eventBus.invokeSubscriber(pendingPost);
//然后,每分发完一次事件都会对比下时间,判断这个method的时间timeInMethod 是否大于等于maxMillisInsideHandleMessage这个最大值时间,若小于就跳出循环,来继续下面的操作
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage)
handleMessage() 循环的源码:
while (true) {
//从前面定义好的queue队列中通过poll方法拉取需要的PendingPost对象
pendingPost实际上就是一个维护着可以复用的对象的复用池
PendingPost pendingPost = queue.poll();
ps:PendingPost是一个arrayList,内部有两个核心方法:获取pendingPost:obtainPendingPost() 和
回收pendingPost:releasePendingPost()
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;//设置标志位为false,说明handler还没有运行
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
(2) 、backgroundPoster = new BackgroundPoster(this);
final class BackgroundPoster implements Runnable
@Override
public void run() {
try {
try {
//在while循环中不断的从队列中获取消息,同样通过类似的eventBus.invokeSubscriber 进行事件的分发
ps:注意这里是有一个限定条件,直到取完池中所以的为止
while (true) {
PendingPost pendingPost =queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
(3) 、asyncPoster = new AsyncPoster(this);
AsyncPoster implements Runnable ,区别与BackgroundPoster:
只获取队列中一个PendingPost,然后进行invokeSubscriber()事件的分发
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
四、EventBus框架的subscribe注解
@Documented //指定为是一个JavaDocument 文档
@Retention(RetentionPolicy.RUNTIME) //指定可以在运行时有效
@Target({ElementType.METHOD}) //指定用来描述方法
public @interface Subscribe{
//线程模式
ThreadModethreadMode() default ThreadMode.POSTING;
boolean sticky() default false; //判断是否为粘性事件
int priority() default 0;
}
ThreadMode 枚举类:
POSTING
/ 默认的线程模式;在执行post操作的时候线程会直接调用订阅者的事件方法
MAIN
/ 在主线程中执行;当发布线程是在主线程可以直接调用该订阅者的方法;否则需要通过handlePost发送消息
BACKGROUND--backgroundPost进行调度(所有队列)
/ 后台线程;表示在后台线程中执行相应的方法,如果发布线程不是在主线程中,不可以直接调用订阅者函数,必须启动唯一的后台线程进行处理,后台线程是唯一的,当事件发送post超过一个的时候会被放置在这里依次处理
ASYNC —asyncPoster 每次只会从队列里获取一个所以不存在卡顿
/ 不论方法线程是在哪个线程都会使用一个空线程进行处理;Async所有的线程都相互独立,不会出现线程卡顿现象
粘性事件
事件消费者在事件发布之后才注册的也能接收到该事件的特殊类型
Sticky Broadcast 粘性广播-传统
粘性广播存在的意义:
在正常情况下,如果发送者发送了某个广播,而接受者在这个广播发送广播之后才注册广播接收者的话,那么广播接收者是无法接受到刚才的广播的。
引入之后:
当接收者注册完之后,还可以接收到刚才发出的广播
在广播发射结束后保存刚刚发送的广播
区别于传统:
Android 的 EventBus会存储所有的Sticky事件,也就是说某个事件不需要的时候就进行手动的移除操作
五、EventBus框架的register订阅者
每新建一个eventbus总线,它的发布和订阅事件都是相互隔离的
举例:创建一个eventbus对象,在这个对象中通过他发布事件;然后又创建一个eventBus对象,在这个eventbus对象中,订阅者是不会收到前一个eventbus所发生的事件的
public void register(Object subscriber) {
//通过反射机制 获取到订阅者的class对象
Class<?> subscriberClass = subscriber.getClass();
//register的核心方法——findSubscriberMethods
通过subscriberMethodFinder找寻器的findSubscriberMethods订阅对象class找到订阅方法的集合,返回一个订阅方法的集合
List<SubscriberMethod> subscriberMethods =
//完成注册订阅的第一步:
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//遍历订阅好的方法集合 ,进行每个方法的订阅操作
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods():
//SubscriberMethod 类型的 List
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
SubscriberMethod:EventBus 总的包装类
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//1、从方法缓存池中查找是否已经有了这个方法,如果有的话就把这个集合返回
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//索引的判断(默认是false) ,所以会进入findUsingInfo()方法
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//获取到订阅方法的集合
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//将subscriberMethods 存储到METHOD_CAHCE当中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
findUsingInfo():
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//1、获取到FindState对象 ,找到订阅过的方法和其状态,如果没有就new 新建一个FindState对象
FindState findState = prepareFindState();
...
ps:FindState(){
定义:
//保存所有订阅方法的ArrayList
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//保存事件类型为key ,订阅类型为value的HashMap
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
// 订阅方法为Methodkey,订阅者的class对象为value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
}
//找到FindState对象的state状态
private FindState prepareFindState() {
//从Find state对象池中查找
synchronized (FIND_STATE_POOL) {
//遍历对象池查找需要的 state对象
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
//已经找到了可用的复用的State,这时候将该位置清空,为了以后可以继续复用它,并返回这个状态给FindState()函数
FIND_STATE_POOL[i] = null;
return state;
}
}
}
//当遍历完整个对象池还没有找到需要的state的时候调用new FindState()创建一个新的state
return new FindState();
}
...
...
findState.initForSubscriber(subscriberClass);
...
//在while 循环结尾 每一次循环之后都会通过moveToSuperclass()进行下一次的循环
while (findState.clazz != null) {
//getSubscriberInfo()函数获取到FindState订阅者的信息
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
//首先获得 findState对象当中的订阅方法的集合
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
//通过for循环进行 订阅方法的遍历
for (SubscriberMethod subscriberMethod : array) {
//订阅方法过滤操作—> 返回true ,订阅好的方法,以及订阅方法的事件类型都是符合它的准则的
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
//将订阅的方法添加到findState的arrayList中,也就是subscriberMethods
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//如果getSubscriberMethods() 返回为null 空,则进入下面
ps:getSubscriberMethods()默认情况下一般都是null
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
findState.checkAdd():
boolean checkAdd(Method method, Class<?> eventType) {
//以eventType事件类型为key,以method为value
//1、anyMethodByEventType.put()会返回之前的方法
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
ps:在eventbus中 有一种特点:
一个订阅者包括订阅者的所有的父类和子类,不会有多个方法,相同的全部去接收同一个事件;
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
throw new IllegalStateException();
}
anyMethodByEventType.put(eventType, this);
}
但有可能子类有可能会订阅该事件,同时它的父类也会订阅该事件的时候,会调用checkAddWithMethodSignature()来根据方法的签名来检查
return checkAddWithMethodSignature(method, eventType);
}
}
checkAddWithMethodSignature():根据方法的签名来检查过滤
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append(‘>‘).append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
//以方法为key,以订阅好的类的class对象为value;
//调用put方法()也会和之前一样会返回之前的订阅的class对象,然后根据class对象进行下一步操作
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//如果这个class对象不存在 ,或者是这个值是method 对象的父类的话就会返回true
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
return true;
} else {
//如果不是的话 ,或是class对象是空,就会把methodKey作为key 添加到subscriberClassByMethodKey 这个HashMap中
ps:这个时候并没有put内容进缓存;因为put的值是methodClassOld是以前的class
put()方法目的是revery:不要出现一个订阅者有多个相同方法,订阅同一个事件,如果有的话就把以前的这个class放到hashMap中去覆盖
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
findUsingReflectionInSingleClass():通过这个方法找到哪些是订阅者订阅好的方法 或是 事件
private void findUsingReflectionInSingleClass(FindState findState) {
…
//1、通过反射的getDeclaredMethods() 获取到订阅者所有的方法
methods = findState.clazz.getDeclaredMethods();
…
//2、对前面获取到的方法进行依次的遍历
for (Method method : methods) {
//3、获取到方法的修饰符 ,然后用这个修饰符进行判断
int modifiers = method.getModifiers();
//4、判断这个方法是否是public 以及该方法的修饰符是否可以忽略
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0){
//5、getParameterTypes()获取方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
//6、进行方法参数的判断是否等于1
ps:eventbus中只允许订阅方法后面的订阅事件是1个,所以通过方法参数长度的判断过滤出参数只有1哥的方法
if (parameterTypes.length == 1) {
//7、调用getAnnotation()方法获取Subscribe对象,用来过滤出只被@Subscribe修饰过的方法
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
…
//8、被subscribeAnnotation过滤好的方法的threadMode()方法获取到相应的线程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
//9、根据不同的线程模式 进行不同的线程调度操作
SubscriberMethod封装的eventbus使用时候所需要的对象添加到FindState 存储方法的集合当中
findState.subscriberMethods.add(
new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
…
}
getMethodsAndRelease():进行返回和释放资源的操作
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//进行资源回收
findState.recycle();
...
}
六、EventBus框架的subscribe 观察者
目标:根据获取到方法的集合单个方法的获取工作
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods =
//完成注册订阅的第一步:
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//下面的目标是:遍历订阅好的方法集合 ,进行每个方法的订阅操作
//建立同步代码块
synchronized (this) {
//遍历获取到的方法集合——
ps:在上一版本中 是通过 获取subscriberMethods的迭代器 ,然后while循环不断的遍历这个迭代器(迭代器.hasNext())
//增强for循环 不断遍历获取到每一个订阅方法
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//完成订阅的第二步:调用该方法完成订阅
ps:
parameter:订阅者-subscriber
parameter:订阅方法-subscriberMethod
subscribe(subscriber, subscriberMethod);
}
}
}
subscribe():
主体流程:
- 1、首先判断是否有注册过该事件;有注册过抛出异常
- 2、按照优先级顺序加入到 subscriptionsByEventType的 value的List中;通过这个HashMap 找到该事件的订阅者、
- 订阅的方法和参数 等等
- 3、再添加到typesBySubscriber的value的List中;通过这个HashMap可以使订阅者找到该订阅者订阅的所有事件
- 4、判断是否是粘性事件、是否有继承关系
- 5、调用checkPostStickyEventToSubscription进行事件的的分发
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//首先获取订阅方法的 事件类型 eventType属性
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
ps:Subscription内部封装了 subscriber订阅者 和 subscriberMethod 订阅方法;
而subscriberMethod又封装了订阅的方法,线程模式,事件类型,优先级,是否是粘性事件等属性。
所以在这里可以看出Subscription 是一个更大的封装类而已
//subscriptionsByEventType这个HashMap的key就是eventType,而value就是subscriptions
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
ps:CopyOnWriteArrayList 是一个可以并发读写的arrayList
//如果subscriptions 为空null,表明这个事件还没有被注册过
if (subscriptions == null) {
//新创建一个arrayList 并把这个arraylist放入到 subscriptionsByEventType 这个HashMap当中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);//为了后期复用
}
//如果这个 subscriptions当中包含了新创建好的newSubscription的话就会抛出异常 ;
异常信息是 该订阅者 已经注册过了该事件 +该事件的类型
else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//获取到集合容纳的大小
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
//根据优先级添加到arrayList当中的制定位置
subscriptions.add(i, newSubscription);
break;
}
}
//以订阅者subscriber为key,以eventType为value,来获取到eventType 的arrayList
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
//新创建一个并填入typesBySubscriber这个HashMap当中
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//将这个事件类型放入到eventType的arrayList当中
subscribedEvents.add(eventType);
//判断订阅方法是否为粘性事件,进一步判断是否支持继承关系
if (subscriberMethod.sticky) {
if (eventInheritance) {
//根据entrySet() 函数获取所有粘性事件的Set集合
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
//依次遍历 并通过eventType.isAssignableFrom()再次判断是否有继承关系
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
//如果有继承关系的话,进行事件的分发操作
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
checkPostStickyEventToSubscription():
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent,
Looper.getMainLooper() == Looper.myLooper() );//通过该标志位判断是否在主线程当中
}
}
postToSubscription(): 核心方法使用的是 线程调度的 三个 post 方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//如果处于POSTING 默认模式 就直接完成线程调用
invokeSubscriber(subscription, event);
break;
case MAIN:
//如果处于Ui主线程中,就直接调用invokeSubscriber
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
//如果不是在主线程,通过handlerPost中的enqueue方法 把需要的 ()入到队列当中
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
//如果在Ui线程 ,就需要通过background 入队列
backgroundPoster.enqueue(subscription, event);
} else {
//如果不在UI线程,区别于MAIN ,可以直接调用
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//不管在哪个线程都会添加到队列当中
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
invokeSubscriber(): //通过反射完成方法的调用
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
七、EventBus框架的Post事件发送 -核心的线程调度
EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
public void post(Object event) {
//通过ThreadLocal 获取到一个发送状态 postingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
ps:PostingThreadState 发送事件的线程类的封装类;
currentPostingThreadState 就是一个ThreadLocal ,线程独有的,不会让其他线程共享当前线程的数据
//获取到事件队列,并将这个事件添加到队列当中
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
//判断是否在进行发送状态,如果发送了就取消操作
if (!postingState.isPosting) {
//获取到Looper判断是否在主线程,获取到当前线程的Looper 和主线程的Looper然后进行对比,如果对比结果isMainThread为true 就继续下面的操作
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
//将isPosting设为true 表示这个事件正在分发了
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//直到整个队列都为空,如果队列不为空则用postSingleEvent()发送事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//将发生状态清零
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postSingleEvent():
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//是否查看与这个事件有关的继承关系
if (eventInheritance) {
//查找到所有继承关系的事件类型
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//如果没有任何的事件,就会调用post(new NoSubscriberEvent() ),表明没有订阅者订阅该事件
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEventForEventType()://获取subscriptionFound 标志位
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//在同步代码块中,通过sbuscriptionsByEventType的HashMap,获取到一个订阅event事件的集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
…
//完成订阅-核心的三个post调度方法
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
…
}