EventBus源码解析

简介

EventBus是安卓事件发布-订阅总线,使用它可以很方便在各组件进行数据传递。它由Event(事件)Subscriber(事件订阅者)、*Publisher(事件发布者)**组成。发布者发布事件后,订阅者可接受数据,并根据需要在不同的线程模型中执行。此外,还支持粘性事件和优先级事件。

一 缓存容器

SubscriberMethod:对订阅方法的封装。包括method、eventType、Subscribe注解中的threadMode、sticky、priority等信息
Subscription: 对subscriber和subscriberMethod的封装
//缓存订阅者和其对应的订阅方法
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//缓存eventType和其对应的方法
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType = new HashMap<>()
//缓存订阅者和其对应的evenTypes,用于反注册
Map<Object, List<Class<?>>> typesBySubscriber = new ConcurrentHashMap<>() 
//缓存事件类型eventType.class和对应的订阅方法method
Map<Class, Object> anyMethodByEventType = new HashMap<>();

二 注册和订阅

1、根据subscriber查询对应的subscriberMethods,并将其缓存到METHOD_CACHE

public void register(Object subscriber) {
	Class<?> subscriberClass = subscriber.getClass();
	//1 查找该订阅者所有的带有@Subscribe注解的方法
	List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
	synchronized (this) {
	    for (SubscriberMethod subscriberMethod : subscriberMethods) {
	        subscribe(subscriber, subscriberMethod);
	    }
	}
 }
 
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
	//2 如果METHOD_CACHE缓存里有该订阅者对应的订阅方法,直接返回
	List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
	 if (subscriberMethods != null) {
	     return subscriberMethods;
	 }
	
	 if (ignoreGeneratedIndex) {
	     subscriberMethods = findUsingReflection(subscriberClass);
	 } else {
	 	 //3 
	     subscriberMethods = findUsingInfo(subscriberClass);
	 }
	 if (subscriberMethods.isEmpty()) {
	     throw new EventBusException("Subscriber " + subscriberClass
	             + " and its super classes have no public methods with the @Subscribe annotation");
	 } else {
	  	 //4 订阅者和其订阅方法缓存到METHOD_CACHE
	     METHOD_CACHE.put(subscriberClass, subscriberMethods);
	     return subscriberMethods;
	 }
}

2、如何查找subscriberMethods

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
	//1、获取或者初始化方法查询对象FindState 
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
        	//如果有,从缓存中遍历
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
        	//2、如果没有,反射获取并缓存
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}
 
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    //3、获取并便利所有订阅方法
    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) {
                    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 (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            	//如果开启严格方法校验,且方法有多个入参,直接抛错
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
        	//如果开启严格方法校验,且方法非Publish修饰,直接抛错
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

3、订阅

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
	Class<?> eventType = subscriberMethod.eventType;
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	if (subscriptions == null) {
	    subscriptions = new CopyOnWriteArrayList<>();
	    //如果enentType对应的subscriptions为空,就新建缓存
	    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 i = 0; i <= size; i++) {
		//根据优先级插入缓存合适的位置
	    if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
	        subscriptions.add(i, newSubscription);
	        break;
	    }
	}
	
	//缓存subscriber和其对应的eventTypes
	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
	if (subscribedEvents == null) {
	    subscribedEvents = new ArrayList<>();
	    typesBySubscriber.put(subscriber, subscribedEvents);
	}
	subscribedEvents.add(eventType);
	
	if (subscriberMethod.sticky) {
	    //处理粘性事件
	    ...
	}
}

发布

public void post(Object event) {
	//获取当前线程存储的postingState
	PostingThreadState postingState = currentPostingThreadState.get();
	List<Object> eventQueue = postingState.eventQueue;
	//把消息放到事件队列
	eventQueue.add(event);
	
	if (!postingState.isPosting) {
	    postingState.isMainThread = isMainThread();
	    postingState.isPosting = true;
	    if (postingState.canceled) {
	        throw new EventBusException("Internal error. Abort state was not reset");
	    }
	    try {
	    	//发送队列里所有事件
	        while (!eventQueue.isEmpty()) {
	            postSingleEvent(eventQueue.remove(0), postingState);
	        }
	    } finally {
	        postingState.isPosting = false;
	        postingState.isMainThread = false;
	    }
	}
}

 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);
	}
	if (!subscriptionFound) {
	    ...
	}
}

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
	CopyOnWriteArrayList<Subscription> subscriptions;
	synchronized (this) {
	    subscriptions = subscriptionsByEventType.get(eventClass);
	}
	if (subscriptions != null && !subscriptions.isEmpty()) {
		//从subscriptionsByEventType中找到与eventClass对应的subscriptions
	    for (Subscription subscription : subscriptions) {
	        postingState.event = event;
	        postingState.subscription = subscription;
	        boolean aborted = false;
	        try {
	        	//把事件分发给订阅者
	            postToSubscription(subscription, event, postingState.isMainThread);
	            aborted = postingState.canceled;
	        } finally {
	            postingState.event = null;
	            postingState.subscription = null;
	            postingState.canceled = false;
	        }
	        if (aborted) {
	            break;
	        }
	    }
	    return true;
	}
	return false;
}
//根据不同的 ThreadMode 进行处理。
//执行线程与目标线程匹配,则直接反射执行;订阅方法不匹配,则先将事件添加到线程对应的Poseter中的PendingPostQueue,然后通过ExecutorService执行
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
	switch (subscription.subscriberMethod.threadMode) {
	    case POSTING:
	        invokeSubscriber(subscription, event);
	        break;
	    case MAIN:
	        if (isMainThread) {
	            invokeSubscriber(subscription, event);
	        } else {
	            mainThreadPoster.enqueue(subscription, event);
	        }
	        break;
	    case MAIN_ORDERED:
	        if (mainThreadPoster != null) {
	            mainThreadPoster.enqueue(subscription, event);
	        } else {
	            // temporary: technically not correct as poster not decoupled from subscriber
	            invokeSubscriber(subscription, event);
	        }
	        break;
	    case BACKGROUND:
	        if (isMainThread) {
	            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);
	}
}

线程调度

MAIN:在主线程执行订阅方法
**enqueue()**时会通过handler向mainLooper发送一条空消息,之后在handler中一次性处理完队列中所有事件,避免频繁占用主线程资源。但是当处理事件总耗时超过maxMillisInsideHandleMessage时,则重新sendMessage(),分批次处理事件,避免占用主线程时间过长导致卡顿。

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.obtainPendingPost(subscription, event);
        synchronized (this) {
        	//向队列添加事件
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                //向mainLoop#MessageQueue发送
                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();
                //DCL双重检查,提升效率
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(pendingPost);
                long timeInMethod = SystemClock.uptimeMillis() - started;
                //当处理时间超过该值后,则重新sendMessage(),分批次处理,避免主线程长时间阻塞
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

BACKGROUND在后台线程执行订阅方法
这是一个任务,用线程池CachedThreadPool执行,这是一种线程数没有限制且立即执行的线程池,但是仍然采用一次性处理完所有事件的策略,因此这种线程模型是在单个后台线程中完成的。

inal 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();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                //CachedThreadPool线程池添加任务
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
            	//一次性完成
                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) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}

ASYNC和BACKGROUND相比,ASYNC直接单开新线程执行本次事件

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);
        eventBus.getExecutorService().execute(this);
    }

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值