如果对EventBus原理不太熟悉的童鞋可以看这个:
1.极其简单的订阅-发布-接收模式
public class Publisher {
private Publisher() {
}
public static Publisher getDefault(){
return PublishHoler.sPublisher;
}
public List<ISubScriber> subscribeByEventTypes=new ArrayList<>();
public void register(ISubScriber subScriber){
subscribeByEventTypes.add(subScriber);
}
public void unRegister(ISubScriber subScriber){
subscribeByEventTypes.remove(subScriber);
}
public void post(EventType eventType){
for(ISubScriber subScriber:subscribeByEventTypes){
subScriber.receive(eventType);
}
}
public static class PublishHoler{
private static Publisher sPublisher=new Publisher();
}
}
public interface ISubScriber {
void receive(EventType eventType);
}
public class EventType {
public String message;
public EventType(String message) {
this.message = message;
}
}
public class Subscriber1 implements ISubScriber {
public Subscriber1() {
Publisher.getDefault().register(this);
}
@Override
public void receive(EventType eventType) {
System.out.println(eventType.message);
}
}
这是一个极其粗糙的订阅发送的例子,完全不能用于生产。
Q:如果有多个订阅者,每个订阅者也有多种感兴趣事件,怎么做到在发送某种事件时,只触发该事件的接收?
A:接收的方法可自行定义,唯一的参数就是发送的事件,添加指定注解(@Subscribe)方便注册时反射查找。
@Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 2)
public void onMessageEvent(NotifyMessage event) {
System.out.println(event.message);
}
//源码里面查找注解
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//todo 找本类的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
//todo 找本类以及父类的所有公共方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//方法的参数类型
if (parameterTypes.length == 1) {
//找到方法上的注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//事件类型就是我们MessageEvent
Class<?> eventType = parameterTypes[0];
//第一次添加
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (....){
}
}
}
Q:使用到了什么设计模式?
A:有两处使用了享元设计模式,使用缓存的对象去处理:
第一处:FindState
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
调用:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
......省略....
return getMethodsAndRelease(findState);
}
第二处:PendingPost
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
Object event;
Subscription subscription;
PendingPost next;
private PendingPost(Object event, Subscription subscription) {
this.event = event;
this.subscription = subscription;
}
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
//从第一个取出来和最后一个取出来都没区别,享元模式而已
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely 这里写10000和写4个没区别??
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
调用:
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
..........
}
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
Q:多个订阅者多个订阅方法怎么保证事件发送的优先级?
A: 根据注解上的优先级调整map顺序
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
..............
//按照优先级对新加入的订阅同一事件的订阅者进行排序
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
Q:为什么发送事件时使用队列(PendingPostQueue)?
A:我觉得没必要使用,其他童鞋能解释下吗?
HandlePoster实现(public class HandlerPoster extends Handler implements Poster)
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
//插进去立马就发送消息
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
BackgroundPoster实现(final class BackgroundPoster implements Runnable, Poster)
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
//后台线程的话,对插入做了一个同步
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
AsyncPoster实现(class AsyncPoster implements Runnable, Poster)
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
//可以多次插入多次调用
eventBus.getExecutorService().execute(this);
}