EventBus 源码解析

EventBus 源码解析

EventBus是一个性能高效的基于观察者模式的事件发布与订阅框架.借助EventBus,我们只需几行代码便能实现组件之间、线程之间的通信

先说明一下EventBus中三个重要的角色:PublisherEventSubscriber. Event:事件,它可以是任意类型,EventBus会根据事件的类型进行全局发送 Pushlisher:事件的发布者,它可以在任意线程中发布事件。在使用时通常调用EventBus.getDefault()方法获取一个EventBus对象,再通过链 式编程调用post()方法进行事件发送 SubScriber:事件接收者 在EventBus3.0之前,使用时必须以OnEvent开头的几种接收方法来接收事件。这些方法分别为:onEventonEventMainThreadonEventBackgroundThreadonEventAsync,但是在3.0之后处理方法可以自定义,但是要以注解@subscribe进行标示, 同时指定线程模型,线程模型默认为POSTING的方式。 Tips:本文分析的源码版本为EventBus:3.2.0

简单用法

在具体的进行源码分析前,我们回顾一下EventBus的使用流程:

java 复制代码
// 1.注册
EventBus.getDefault().register(this);
// 2.准备订阅方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(SayHelloEvent event) {
String message = event.getMessage();
...
}
// 3.发布事件
EventBus.getDefault().post(new SayHelloEvent("Hello,EventBus!!!"));
//4.反注册
EventBus.getDefault().unregister(this);

事件订阅发布的流程分析

我们就从用法入手,逐步分析EventBus事件发布订阅的流程.

EventBus.getDefault()创建EventBus对象

EventBus使用的过程中,不管是注册、解注册或者是发送事件都会用到这个方法,所以我们首先看一下这个方法中都是做了什么。

java 复制代码
public class EventBus{
    
    /** Log tag, apps may override it. */
	public static String TAG = "EventBus";
    
	static volatile EventBus defaultInstance;
    
	private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
	private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
    
	private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
	private final Map<Object, List<Class<?>>> typesBySubscriber;
	private final Map<Class<?>, Object> stickyEvents;
    
	private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
		@Override
			protected PostingThreadState initialValue() {
			return new PostingThreadState();
		}
	};
    
    ......
    ......
    /** Convenience singleton for apps using a process-wide EventBus instance. */
	// 单例,double check
	public static EventBus getDefault() {
			EventBus instance = defaultInstance;
			if (instance == null) {
				synchronized (EventBus.class) {
				instance = EventBus.defaultInstance;
				if (instance == null) {
					instance = EventBus.defaultInstance = new EventBus();
				}
			}
		}
		return instance;
	}
    
    public EventBus() {
		this(DEFAULT_BUILDER);
	}
    
    // eventBus的具体构建通过bulier模式完成
	EventBus(EventBusBuilder builder) {
		logger = builder.getLogger();
		//这个集合可以根据事件类型获取订阅者
		//key:事件类型class,value:CopyOnWriteArrayList<Subscription>订阅该事件的订阅者集合
		subscriptionsByEventType = new HashMap<>();
		//订阅者所订阅的事件集合
		//key:订阅者,value:List<Class<?> 该订阅者订阅的事件类型集合
		typesBySubscriber = new HashMap<>();
		//粘性事件集合
		//key:事件Class对象,value:事件对象
		stickyEvents = new ConcurrentHashMap<>();
		// 是否支持Android mainThread
		mainThreadSupport = builder.getMainThreadSupport();
		// Android mainThread 事件发送者
		mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
		// 后台线程事件发送者
		backgroundPoster = new BackgroundPoster(this);
		// 异步线程事件发送者
		asyncPoster = new AsyncPoster(this);
		indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() :0;
		// 订阅者订阅事件查找者
		subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
		builder.strictMethodVerification, builder.ignoreGeneratedIndex);
		......
		......
		// private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
		executorService = builder.executorService;
	}  
}

EventBus通过EventBusBuilder来初始化EventBus对象,通过单例模式对外公开这个实例. subscriptionsByEventTypetypesBySubScriberstickEventssubcriberMethodFinder几个属性比较重要,后续分析中会经常提到,先有个印象.

Tips: 我们可以通过EventBusBuilder来自定义配置一个EventBus对象实例.

register(Object subscriber)

创建EventBus对象之后需要将事件订阅者在EventBus中进行注册。

JAVA 复制代码
public void register(Object subscriber) {
		Class<?> subscriberClass = subscriber.getClass();
		// 解析subscriber类中@Subscribe标记的方法,返回一个List<SubscriberMethod>
		List<SubscriberMethod> subscriberMethods =
		subscriberMethodFinder.findSubscriberMethods(subscriberClass);
		synchronized (this) {
		// 遍历集合注册事件的subscriber;
		for (SubscriberMethod subscriberMethod : subscriberMethods) {
				subscribe(subscriber,subscriberMethod);
			}
		}
}

register()方法主要做了两件事情:

  • 解析subscriber对象中被@Subscribe标记的方法
  • 注册事件的Subscriber

subscriberMethodFinder.findSubscriberMethods(subscriberClass)完成了@Subscribe标记方法的解析,此步骤的具体实现不影响我们 分析事件的发布流程(后面会分析具体流程),先看看解析返回的数据

@Subscribe

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME) // @Subscribe注解在运行时依然存在
@Target({ElementType.METHOD})
public @interface Subscribe {
	// 事件订阅执行时的线程类型;
	ThreadMode threadMode() default ThreadMode.POSTING;
	// 是否是粘性事件
	boolean sticky() default false;
	//事件被执行的优先级,优先级越高,越早执行
	int priority() default 0;
}

SubscriberMethod.java

java 复制代码
public class SubscriberMethod {
    
	final Method method; // @Subscribe标记的方法的method
	final ThreadMode threadMode; // 线程类型
	final Class<?> eventType; // 方法参数的calss,事件的Class对象
	final int priority; //优先级
	final boolean sticky; //是否是粘性;
	/** Used for efficient comparison */
	String methodString;
	public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
		this.method = method;
		this.threadMode = threadMode;
		this.eventType = eventType;
		this.priority = priority;
		this.sticky = sticky;
	}
	...
	...
}

List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass) 完成@Subscribe注解解析,返回了解析结果 , SubscriberMethod记录了@Subscribe标记的method对象和@Subscribe的值。接着注册事件的Subscriber。

java 复制代码
		// 遍历集合注册事件的subscriber;
		for (SubscriberMethod subscriberMethod : subscriberMethods) {
				subscribe(subscriber,subscriberMethod);
			}
		}

subscribe(Object subscriber, SubscriberMethod subscriberMethod)

java 复制代码
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //step1:
	// 获取当前观察的事件类型
	Class<?> eventType = subscriberMethod.eventType;
	// 封装成一个Subscription对象
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
	//通过事件类型获取该事件的订阅者集合;
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	if (subscriptions == null) {
		subscriptions = new CopyOnWriteArrayList<>();
		subscriptionsByEventType.put(eventType, subscriptions);
	} else {
		if (subscriptions.contains(newSubscription)) {
			throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
		}
	}
	int size = subscriptions.size();
	// 按照priority的高低进行排序,将数据保存到EventBus的subscriptionsByEventType属性里面
	for (int i = 0; i <= size; i++) {
	if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
		subscriptions.add(i, newSubscription);
			break;
		}
	}
    //step2:
	// 记录注册对象观察的事件类型,反注册时会用到;
	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
	if (subscribedEvents == null) {
		subscribedEvents = new ArrayList<>();
		typesBySubscriber.put(subscriber, subscribedEvents);
	}
	subscribedEvents.add(eventType);
	// 方法被标记为接收stick,后面会分析stick事件
	if (subscriberMethod.sticky) {
		...
		...
	}
}

先看step1干了什么?

subscribersubscriberMethod被包装成了Subscription , 为啥不直接用SubscriberMethod ? 看看Subscription里面有啥

Subscription.java

java 复制代码
final class Subscription {
	final Object subscriber; //@subscribe注解标记方法的持有对象
	final SubscriberMethod subscriberMethod; //@Subscribe标记的方法解析后的数据
	volatile boolean active;
	Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
		this.subscriber = subscriber;
		this.subscriberMethod = subscriberMethod;
		active = true;
	}
	...
	...
}

联想到Method的invoke()方法

java 复制代码
// obj:方法的持有者的实例
// args:方法参数的实例
Object invoke(Object obj,Object...args)

obj对应subscriber , method对象本身均保存在subscriberMethod 中,如果再获取args,订阅方法执行的数据就都有了,接着看往下看:

java 复制代码
	Class<?> eventType = subscriberMethod.eventType;
	// 封装成一个Subscription对象
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取该事件类型的Subscription集合,如果没有,就创建一个新的list放进去
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	if (subscriptions == null) {
		subscriptions = new CopyOnWriteArrayList<>();
		subscriptionsByEventType.put(eventType, subscriptions);
	} else {
		if (subscriptions.contains(newSubscription)) {
			throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
		}
	}
	int size = subscriptions.size();
	// 按照priority的高低进行排序,将Subscription数据保存进去
	for (int i = 0; i <= size; i++) {
	if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
		subscriptions.add(i, newSubscription);
			break;
		}
	}

ok , subscriptionsByEventType里面保存了事件Class --- List<Subscription>的映射关系

画张图示意一下:

接着看step2做了什么

java 复制代码
    //获取subscriber观测事件类型的集合
	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
	if (subscribedEvents == null) {
		subscribedEvents = new ArrayList<>();
		typesBySubscriber.put(subscriber, subscribedEvents);
	}
	subscribedEvents.add(eventType);

与上面一样,subscribedEvents里面保存了订阅者subscriber --- List<事件Class>的集合映射

总结一下,register(Object subscriber)执行完成后

  • subscriber的注解数据保存到了EventBus对象的subscriptionsByEventType属性里面,通过Event的calss, 可以获取对应的Subscription , Subscription里面保存了@Subscriber标记的method执行需要的数据
  • subscriber订阅的事件类型 保存到了EventBus对象的subscribedEvents里面 , subscribedEvents里面保存了subscriber订阅的事件Class集合

post(Object event)

java 复制代码
/** Posts the given event to the event bus. */
public void post(Object event) {
	//因为可以在不同的线程中执行post方法,为了避免事件同步等操作,为不同的线程提供事件执行的环境
	//ThreadLocal原理;
	PostingThreadState postingState = currentPostingThreadState.get();
	// 事件被触发前缓存到这里;
	List<Object> eventQueue = postingState.eventQueue;
	eventQueue.add(event);
	if (!postingState.isPosting) {
		postingState.isMainThread = isMainThread();
		postingState.isPosting = true;
		...
		//触发事件
		postSingleEvent(eventQueue.remove(0), postingState);
		...
	}
}

PostingThreadState提供事件分发的执行环境,接着看postSingleEvent(eventQueue.remove(0), postingState)

java 复制代码
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
	Class<?> eventClass = event.getClass();
	boolean subscriptionFound = false;
	//事件是否支持继承结构?
	//比如有两个Event a 和 Event b , a extends b
	// 我们post event a ,由于a也可以看作一个b对象,所以也需要触发 event b;
	if (eventInheritance) {
		// 查找事件calss所有的superClass和interface,将其作为潜在的事件类型;
		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);
	}
	if (!subscriptionFound) {
		// post(new NoSubscriberEvent(this, event));
		...
		...
	}
}

接着看postSingleEventForEventType(event, postingState, clazz);

java 复制代码
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
	CopyOnWriteArrayList<Subscription> subscriptions;
	synchronized (this) {	
		//通过subscriptionsByEventType获取事件的Subscribers;
		subscriptions = subscriptionsByEventType.get(eventClass);
	}
	// 遍历执行订阅,由于register的时候根据priority排过顺序,proprity最大的会被先执行;
	if (subscriptions != null && !subscriptions.isEmpty()) {
			for (Subscription subscription : subscriptions) {
					postingState.event = event;
					postingState.subscription = subscription;
					...
					//触发Subscriber的onEvent
					postToSubscription(subscription, event, postingState.isMainThread);
					...
				}
		return true;
	}
	return false;
}

通过事件的class 找到事件的订阅者subscriptions , 按照顺序依次执行订阅方法 , 说好的Eventbus切换线程呢?,接着跟

java 复制代码
private void postToSubscription(Subscription subscription, Object event,boolean isMainThread){
    
    // 根据threadMode,切换不同的线程或直接执行
    switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
				// 直接执行订阅;
				invokeSubscriber(subscription, event);
				break;
			case MAIN:
            	if (isMainThread) {
					// 当前线程就是主线程,直接执行订阅;
					invokeSubscriber(subscription, event);
				}else{
                    //添加到mainThreadPoster的队列中去,在主线程中调用响应方法
                     mainThreadPoster.enqueue(subscription, event);
                }
            	break;
            case MAIN_ORDERED:
            	if (mainThreadPoster != null) {
                    // 主线程优先模式
                    mainThreadPoster.enqueue(subscription, event);
                }else{
                    //如果不是主线程就在当前线程中进行执行订阅
                    invokeSubscriber(subscription, event);
                }
            	break;
        	case BACKGROUND:
            	if (isMainThread){
                    // 如果是主线程,进入backgroundPoster队列中等待被执行;
                    backgroundPoster.enqueue(subscription, event);
                }else{
                    //直接执行订阅;
                    invokeSubscriber(subscription, event);
                }
            	break;
            case ASYNC:
            	//不管是不是在主线程中,都会在子线程中调用响应方法
				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, event);
	} catch (InvocationTargetException e) {
		handleSubscriberException(subscription, event, e.getCause());
	} catch (IllegalAccessException e) {
		throw new IllegalStateException("Unexpected exception", e);
	}
}

事件订阅执线程的切换分五种模式

  • POSTING :当前线程直接执行

  • MAIN : Android 主线程执行

  • MAIN_ORDERED: 如果支持主线程执行那么让主线程执行,如果不支持主线程,直接在当前线程执行

  • BACKGROUND : 如果在主线程,切换到后台线程执行,不是主线程,直接执行

  • ASYNC:另开线程执行

Event是如何切换线程的

Event切换线程执行是通过对应的Poster来实现的,下面就具体分析一下不同类型的poster

Poster.java
java 复制代码
// 定义了事件进入队列,事件的具体执行由其子类完成;
interface Poster {
	/**
	* Enqueue an event to be posted for a particular subscription.
	*
	* @param subscription Subscription which will receive the event.
	* @param event Event that will be posted to subscribers.
	*/
	void enqueue(Subscription subscription, Object event);
}

Main线程的HandlerPoster

mainThreadPoster的实例是通过mainThreadSupport.createPoster(this)来创建的,最终返回的是HandlderPoster的一个实例

java 复制代码
public class HandlerPoster extends Handler implements Poster{
    
    private final PendingPostQueue queue;
	private final int maxMillisInsideHandleMessage;
	private final EventBus eventBus;
	private boolean handlerActive;
    
    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
		super(looper);
		this.eventBus = eventBus;
		this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
		queue = new PendingPostQueue();
	}
    
    public void enqueue(Subscription subscription, Object event) {
		// 包装一下订阅执行数据,PendingPost内部也使用享元模式;
		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");
				}
			}
		}
	}
    
    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try{
            long started = SystemClock.uptimeMillis();
            while(true){
                //从队列中取出数据;
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null){
                    // Check again, this time in synchronized
                    synchronized (this){
                       pendingPost = queue.poll(); 
                        if (pendingPost == null){
                            handlerActive = false;
                            return;
                        }
                    }
                    // 切换到主线程执行;
					eventBus.invokeSubscriber(pendingPost);
                }
            }
        }finally{
            handlerActive = rescheduled;
        }
    }
    
    void invokeSubscriber(PendingPost pendingPost){
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active){
            // 实际还是调用的invokeSubscriber
            invokeSubscriber(subscription, event);
        }
    }
      
}
  • HandlerPoster通过handdler的原理,将事件执行切换到main线程。

ASYNC 额外开启异步线程 AsyncPoster.java

java 复制代码
class AsyncPoster implements Runnable, Poster {
    
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    
    AsyncPoster(EventBus eventBus){
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }
    
    public void enqueue(Subscription subscription, Object event){
        // 数据包装;
		PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        // 数据入队列;
        queue.enqueue(pendingPost);
        // 执行run方法,开新的线程;
        eventBus.getExecutorService().execute(this);
    }
    
    @Override
	public void run() {
		// 获取订阅数据;
		PendingPost pendingPost = queue.poll();
		if(pendingPost == null) {
			throw new IllegalStateException("No pending post available");
		}
		// 事件具体执行位置,实现是在eventBus.getExecutorService()指定的线程
		eventBus.invokeSubscriber(pendingPost);
	}
}
  • asyncPoster执行事件在eventBus.getExecutorService()的线程池的线程里面,每次发布事件都会在新线程里面执行
JAVA 复制代码
// EventBus的默认线程池,每次执行runnable都是新开线程;
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

/*
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}*/

BACKGROUND 后台线程执行事件

java 复制代码
final class BackgroundPoster implements Runnable, Poster{
    
    private final PendingPostQueue queue;
	private final EventBus eventBus;
    private volatile boolean executorRunning;
    
    BackgroundPoster(EventBus eventBus) {
		this.eventBus = eventBus;
		queue = new PendingPostQueue();
	}
	// 事件进入backgroundPoster后是按照顺序执行的,每一批执行事件都是在同一个线程里面,下一批次事件执行会开启一个新的线程;
    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);
           } 
        }
    }
    
    @Override
	public void run() {
        try{
            //循环,每次执行都是将队列里面的事件全部执行完后才退出线程;
            while(true){
                PendingPost pendingPost = queue.poll(1000);
                if (pendingPost == null) {
                    synchronized (this) {
                        pendingPost = queue.poll();
                        if (pendingPost == null){
                            executorRunning = false;
                            return;
                        }
                    }
                }
                // 事件执行;
                eventBus.invokeSubscriber(pendingPost);
            }
        }catch(){
            eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
        }finally{
            executorRunning = false;
        }
    }
    
}
  • backgroundPoster执行事件也是在eventBus.getExecutorService()的线程池的线程里面,直到当前队列里面事件执行完成之前,不会开启新的 线程来执行事件,事件的执行过程是串联起来的.也可以理解为事件是分批次来执行的,不同批次会开不同的线程执行,同一批次里面的事件在同 一个线程里面按照串联顺序依次执行.

unregister(Object subscriber)

EventBus.getDefault()返回的是一个单例对象,保存在subscriptionsByEventType中的Subscribers不使用时需要清除避免内存泄漏.

java 复制代码
public synchronized void unregister(Object subscriber) {
	// 获取订阅对象拥有的所有事件类型,register时保存过subscriber观察的事件种类;
	List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
	if (subscribedTypes != null) {
		for (Class<?> eventType : subscribedTypes) {
			// 注销每种事件类型对应的Subscription;
			unsubscribeByEventType(subscriber, eventType);
		}
		typesBySubscriber.remove(subscriber);
	} else {
		...
	}
}

// 注销每种事件类型对应的Subscription,防止内存泄漏;
private void unsubscribeByEventType(Object subscriber, Class<?> eventType){
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null){
        int size = subscriptions.size();
        for (int i = 0; i < size; i++){
            Subscription subscription = subscriptions.get(i);
            if (subscription.subscriber == subscriber){
                subscription.active = false;
                subscriptions.remove(i);
                i--;
				size--;
            }
        }
    }
}

OK , EventBus的主体流程就到处结束了

补充

Stick事件

stick事件与一般事件的区别在于stick事件的执行时机

java 复制代码
public void postSticky(Object event){
    synchronized (stickyEvents){
       // 将事件存入stickyEvents容器内
       stickyEvents.put(event.getClass(), event);
    }
    // 此时只是当作普通事件被post;
    post(event);
}

// 移除stickevnet;
public <T> T removeStickyEvent(Class<T> eventType){
    synchronized (stickyEvents){
        return eventType.cast(stickyEvents.remove(eventType));
    }
}

stick事件是在register时触发的,看一下register方法内部的subscribe方法:

java 复制代码
subscribe(Object subscriber, SubscriberMethod subscriberMethod){
    Class<?> eventType = subscriberMethod.eventType;
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
	......
	......
	if (subscriberMethod.sticky){
    // 默认eventInheritance = true;
    	if (eventInheritance){
        	// 遍历stickEvents容器,postStick的stick事件会被存进去, key是事件的calss对象,value是event实例
       		 Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); 
        	for (Map.Entry<Class<?>, Object> entry : entries){
           		 Class<?> candidateEventType = entry.getKey();
            	// a.isAssignableFrom(b),a为b的父类或者接口|a与b是同一个类或者接口;
            	if (eventType.isAssignableFrom(candidateEventType)){
                    Object stickyEvent = entry.getValue();
                    // 触发stickEvent,注意post的event对象是之前存储在stickyEvents中的对象;
                    checkPostStickyEventToSubscription(newSubscription,stickyEvent);
            	}
        	}
    	}else{
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
	}    
}

// 执行事件订阅,与上面post方法殊途同归
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent){
    if (stickyEvent != null) {
		postToSubscription(newSubscription, stickyEvent, isMainThread());
	}
}

@Subscribe注解的解析的过程

最后补充一下@Subscribe的解析过程

SubscriberMethodFinder.java
java 复制代码
class SubscriberMethodFinder{
    
    private static final int BRIDGE = 0x40;
    private static final int SYNTHETIC = 0x1000;
    private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
    
    private List<SubscriberInfoIndex> subscriberInfoIndexes;
    private final boolean strictMethodVerification; // 是否开启严格验证
    private final boolean ignoreGeneratedIndex;
    private static final int POOL_SIZE = 4;
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
    
    SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
			boolean ignoreGeneratedIndex){
        this.subscriberInfoIndexes = subscriberInfoIndexes;
        this.strictMethodVerification = strictMethodVerification; // 默认false;
        this.ignoreGeneratedIndex = ignoreGeneratedIndex; // 默认false;
    }
    
    ......
    ......
        
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass){
        // 有缓存,直接从缓存中拿
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
			return subscriberMethods;
		}
        if (ignoreGeneratedIndex) {
            // 通过反射来解析数据;
            subscriberMethods = findUsingReflection(subscriberClass);
        }else{
            // 通过apt来获取解析数据;
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        // 如果一个subscribe注解方法都没有找到,throw exception(),是不是见过这个异常
        if (subscriberMethods.isEmpty()) {
			throw new EventBusException("Subscriber " + subscriberClass
			+ " and its super classes have no public methods with the @Subscribe annotation");
		}else {
            // 记录一下,第二次使用时直接使用缓存;
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }  
    }
    
    //  通过反射来解析@Subscribe,数据的解析实际上放到了FindState类里面处理
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState(); // 享元模式
        findState.initForSubscriber(subscriberClass);
        // 切换到父类class,这样父类calss里面的@subscribe注解的方法也可以解析到
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    
    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();
    }
     
    // 解析@Subscribe注解的辅助类
    static class FindState{
        
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
		final Map<Class, Object> anyMethodByEventType = new HashMap<>();
		final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
		final StringBuilder methodKeyBuilder = new StringBuilder(128);
        
        ......
        ......
        
       	 	//把当前class设置为父类class,过滤系统层面calss,防止无限制的解析
        	void moveToSuperclass() {
            	if (skipSuperClasses) {
                	clazz = null;
            	} else {
                	clazz = clazz.getSuperclass();
                	String clazzName = clazz.getName();
                	/** Skip system classes, this just degrades performance. */
                	if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                    	clazz = null;
               		 }
            	}
        	} 
            
    }
    
   
    // 解析@Subscribe的核心方法,结果保存再FindState的一个List<SubscriberMethod>属性下面
    private void findUsingReflectionInSingleClass(FindState findState){
        Method[] methods;
        try{
           // 获取class自己声明的方法,包括private的方法; 
            methods = findState.clazz.getDeclaredMethods();
        }catch(Throwable th){
            try{
                //获取class的publish方法,包括继承得来的方法;
                methods = findState.clazz.getMethods();
            }catch(LinkageError error){
                ......
                throw new EventBusException(msg, error);
            }
            findState.skipSuperClasses = true;
        }
        for (Method method : methods){
            int modifiers = method.getModifiers();
            // 通过方法修饰符过滤一下,要public,非abstract,非static, 非synthetic,非bridge,bridge是啥我也不知道
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0){
                Class<?>[] parameterTypes = method.getParameterTypes();
                // 再过滤一下,只能是参数只有一个的方法,eventbus不支持参数 > 1
                if (parameterTypes.length == 1){
                    // 获取@Subscribe注解对象;
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    //有@subscribe,目标命中
                    if (subscribeAnnotation != null){
                        // 该方法只有一个事件对象作为参数,获取事件对象类型;
                        Class<?> eventType = parameterTypes[0];
                        //防止重写父类中的方法造成重复添加;
                        if (findState.checkAdd(method, eventType)){
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 将@Subscribe注解的解析结果保存到SubscriberMethod对象中;
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
								subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                }else if(strictMethodVerification && method.isAnnotationPresent(Subscribe.class)){
                    // 开启严格校验模式下,@Subscribe标记的方法的参数个数不为1会抛异常;
                    ......
                    ......
                    throw new EventBusException("@Subscribe method " + methodName +
					"must have exactly 1 parameter but has " + parameterTypes.length);    
                }  
            }else if(strictMethodVerification && method.isAnnotationPresent(Subscribe.class)){
                // 如果开启了严格校验,@Subscribe标记的方法的修饰符不满足要求会抛异常
                ......
               throw new EventBusException(methodName +" is a illegal @Subscribe method: must be public, non-static, and non-								abstract");     
            }
           
        }
    }
    
    
}
相关推荐
Mckay882 小时前
android studio导入项目
android·ide·android studio
是店小二呀4 小时前
【优选算法 | 字符串】字符串模拟题精选:思维+实现解析
android·c++·算法
奔跑吧 android5 小时前
【android bluetooth 协议分析 12】【A2DP详解 1】【车机侧蓝牙音乐免切源介绍】
android·bluetooth·bt·gd·a2dpsink·免切源·aosp14
飞猿_SIR6 小时前
Android Exoplayer多路不同时长音视频混合播放
android·音视频
前端懒猫6 小时前
android实现USB通讯
android
jiet_h7 小时前
Android锁
android
teacher伟大光荣且正确15 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt
飞猿_SIR18 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen9919 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇1 天前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos