EventBus源码分析

前言:已将EventBus用于了多个项目,最近研究了EventBus的源码,在此记录一下研究及学习历程。(注:本文记录的是2.4.0的版本)

一、概述

EvetnBus是一款为Android打造的订阅/发布事件总线,可以代替BroadCast、Handler等在Activity等组件间传递消息。

二、使用简介

  • 首先,建一个消息类,如MsgEvent,里面可随便定义变量,也可用已有的类。
public class MsgEvent {

    private String msg;

    public MsgEvent(String msg) {
       this.msg = msg;
    }

    public String getMsg() {
       return msg;
    }

   public void setMsg(String msg) {
       this.msg = msg;
   }
}
  • 在需要接收消息的类里进行消息订阅(如在Activity的onCreate中进行注册,以下的消息订阅者均以Activity示例)
@Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     EventBus.getDefault().register(this);
 }
  • 在需要接收消息的类里需定义相应的消息处理方法,该方法以“onEvent”字符串开头,且符合EventBus的四种接收方法的命名(即订阅函数,请看源码解析部分)。
public void onEventMainThread(MsgEvent event){
     Log.w("----onEventMainThread----",event.getMsg()+"");
}
  • 在需要发布事件的地方,进行事件发布。
EventBus.getDefault().post(new MsgEvent("msg"));
  • 最后,若不想再接收消息,则取消订阅即可。
@Override
protected void onDestroy() {
    super.onDestroy();
    EventBus.getDefault().unregister(this);
}

三、源码分析

1、订阅函数

在分析源码之前,简单介绍一下EventBus的四类订阅函数。(即:前面提到的以“onEvent”开头的消息接收方法)。

  • onEvent:使用onEvent作为订阅函数,该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,即发布事件和接收事件线程在同一个线程。
  • onEventAsync:使用onEventAsync作为订阅函数,无论事件在哪个线程发布,都会创建新的子线程在执行此方法。
  • onEventMainThread:使用onEventMainThread作为订阅函数,无论事件是在哪个线程中发布出来的,都会在UI线程中执行,接收事件就会在UI线程中运行。
  • onEventBackground:使用onEventBackgrond作为订阅函数,若事件是在UI线程中发布出来的,
    就会在子线程中运行;若事件本来就是子线程中发布出来的,onEventBackground函数直接在该子线程中执行。

2、核心类介绍

这里写图片描述

2.1EventBus.java

EventBus是整个事件最关键的功能类,以单例的方式提供入口给订阅者和发布者,同时提供对外的API(如订阅API,发布API,取消订阅API)。

2.1.1关键成员变量
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();

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

private final HandlerPoster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
private final SubscriberMethodFinder subscriberMethodFinder;
private final ExecutorService executorService;
  • eventTypesCache:该成员是一个Map集合,以事件类型为key,事件类型列表为value(列表存储:事件的所有父类和接口的Class类型)。当发布一个事件的时候,首先根据该事件的类型查找之前有没有发送过同样的事件,如果没有则进行缓存。
  • subcriptionByEventType:该成员是一个Map集合,以事件类型为key,事件类型对应的订阅者列表为value。
  • typesByScriscriber:该成员是一个Map集合,以订阅者为key,订阅者对应的事件类型列表为value.
  • stickEvent:该成员是一个sticky事件变量,当事件发布后,若有订阅者开始订阅该类型事件,依然能收到该事件最近一个Sticky事件。
  • currentPostingThreadState:该成员是ThreadLocal变量,存储了当前线程的Post信息。
  • mainThreadPoster:该成员是一个Handler变量,在主线程中执行订阅方法。
  • backgroundPoster:该成员是一个Runnable变量,在子线程中执行订阅方法。
  • asyncPoster:该成员变量是一个Runnable变量,在子线程中执行订阅方法。
  • subscriberMethodFinder:查找订阅事件相关的功能类。
  • executorService:线程池变量。
2.1.2EventBus入口方法
public static EventBus getDefault() {
     if (defaultInstance == null) {
         synchronized (EventBus.class) {
             if (defaultInstance == null) {
                 defaultInstance = new EventBus();
             }
         }
     }
     return defaultInstance;
 }

getDefault方法创建EventBus的单例模式,初始化线程池等相关变量。

2.1.3事件订阅(事件注册)
public void register(Object subscriber) {
	register(subscriber, false, 0);
}

无论是以哪种事件注册,最终都将执行以下方法:

private synchronized void register(Object subscriber, boolean sticky, int priority){
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        subscribe(subscriber, subscriberMethod, sticky, priority);
    }
}
  • 第2行:通过subscriberMethodFinder查找订阅者中对应的所有订阅函数,并以List的形式返回数据,SubcriberMethod封装了“订阅者,订阅函数,订阅函数对应的线程模式”。
  • 第3行:遍历每个订阅方法,执行subscribe方法。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean 		sticky, int priority) {
	//获取订阅的事件类型(即消息类型)
	Class<?> eventType = subscriberMethod.eventType;
	//根据事件类型获取其对应的Subscription列表(Subscription成员变量:订阅者,subscriberMethod,优先级)
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	//创建Subscription
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
	if (subscriptions == null) {
		subscriptions = new CopyOnWriteArrayList<Subscription>();
		subscriptionsByEventType.put(eventType, subscriptions);
	} else {
		if (subscriptions.contains(newSubscription)) {
			throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);
		}
	}
	//遍历Subscription列表
	int size = subscriptions.size();
	for (int i = 0; i <= size; i++) {
		//比较新建的Subscription的优先级和列表中的其他项,
		//只要查找到优先级高于第i项,则插入到当前位置,退出循环;反之添加到列表末尾
		if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
			subscriptions.add(i, newSubscription);
			break;
		}
	}

	//根据订阅者获取其对应的事件类型列表
	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
	if (subscribedEvents == null) {
		subscribedEvents = new ArrayList<Class<?>>();
		typesBySubscriber.put(subscriber, subscribedEvents);
	}
	//添加事件类型至列表
	subscribedEvents.add(eventType);

	if (sticky) {
		Object stickyEvent;
		synchronized (stickyEvents) {
			stickyEvent = stickyEvents.get(eventType);
		}
		if (stickyEvent != null) {
			// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
			// --> Strange corner case, which we don't take care of here.
			postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
		}
	}
 }
2.1.4事件注销
public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
  • 第2行:获取订阅者对应的事件列表
  • 第4-7行:遍历事件列表,执行unubscribeByEventType方法,从subscriptionEventType中移除前订阅者;从typeBysubscriber移除当前订阅者。
2.1.4事件发布
public void post(Object event) {
     PostingThreadState postingState = currentPostingThreadState.get();
     List<Object> eventQueue = postingState.eventQueue;
     eventQueue.add(event);
     if (!postingState.isPosting) {
         postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
         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;
         }
     }
 }
  • 第2行:获取当前线程的Post信息(PostingThreadState成员变量:事件队列,post事件是否在主线程,
  • 是否正在分发,订阅者信息,是否取消)。
  • 第4行:将事件添加到Post队列中。
  • 第5-7行:当前线程未进行事件分发时,重置Post的信息(重置isMainThread,标示isPosting正在分发)。
  • 第11-15行:循环遍历事件队列,通过posSingleEvent方法,进行事件发布。
  • 第16-17行:重置当前线程的Post信息(标示isMainThread为false,标示isPosting为未分发状态)

posSingleEvent方法:

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) {
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
}
  • 第4行:判断是否发布有继承关系类型的事件
  • 第5行:查找与事件类型有关的所有类型,包括它的父类及他实现的接口(查找方法:
  • lookupAllEventTypes)
  • 第7-8行:遍历类型列表,进行事件发布(发布方法:postSingleEventForEventType)。

lookupAllEventTypes方法

private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
     synchronized (eventTypesCache) {
         List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
         if (eventTypes == null) {
             eventTypes = new ArrayList<Class<?>>();
             Class<?> clazz = eventClass;
             while (clazz != null) {
                 eventTypes.add(clazz);
                 addInterfaces(eventTypes, clazz.getInterfaces());
                 clazz = clazz.getSuperclass();
             }
             eventTypesCache.put(eventClass, eventTypes);
         }
         return eventTypes;
     }
 }

postSingleEventForEventType方法

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
     CopyOnWriteArrayList<Subscription> subscriptions;
     synchronized (this) {
         subscriptions = subscriptionsByEventType.get(eventClass);
     }
     if (subscriptions != null && !subscriptions.isEmpty()) {
         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;
 }
  • 第4行:获取事件类型对应的订阅者列表。
  • 第7-22行:遍历订阅这列表,通过postToSubscription方法对订阅者进行消息发布。

postToSubscription方法

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
            break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BackgroundThread:
            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);
    }
}
  • 第3-5行:如果订阅者对应的订阅方法线程模式是PostThread,则在当前线程调用订阅方法。
  • 第6-12行:如果订阅者对应的订阅方法线程模式是MainThread,若当前线程为主线程,则直接调用订阅方法;反之,通过mainThreadPoster的Handler机制在主线程调用订阅方法。
  • 第13-19行:如果订阅者对应的订阅方法线程模式是BackgroundThread,若当前线程为主线程,则通过backgroundPoster异步执行订阅方法;反之在当前线程执行订阅方法。
  • 第20-22行:如果订阅者对应的订阅方法线程模式是Async,都通过asyncPoster异步执行订阅方法。

总结:无论订阅者对应的订阅方法是哪种线程模式,都将通过invokeSubscriber方法以反射机制来执行订阅方法。

void invokeSubscriber(PendingPost pendingPost) {
    Object event = pendingPost.event;
    Subscription subscription = pendingPost.subscription;
    PendingPost.releasePendingPost(pendingPost);
    if (subscription.active) {
        invokeSubscriber(subscription, event);
    }
}

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);
    }
}
2.2 SubscriberMethodFinder.java

提供订阅者相关信息的存储和查找功能。

2.2.1关键成员
private static final Map<String, List<SubscriberMethod>> methodCache = new HashMap<String, List<SubscriberMethod>>();

methodCache:是一个HashMap的变量,以订阅者类名为key,SubscriberMethod对象为元素的ArrayList为value。
#####2.2.2关键方法(订阅者信息的存储和查找方法)
findSubscriberMethods方法查找订阅者对应的SubscriberMethod(包括订阅者,订阅方法,订阅方法对应线程模式)列表时,先查看是否在此缓存变量中,如果存在,则直接返回列表;反之,通过反射方法查找自己及父类的订阅方法(并封装成SubscriberMethod),然后存储到methodCache,同时返回对应的SrubscriberMethod列表。

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
   String key = subscriberClass.getName();
   List<SubscriberMethod> subscriberMethods;
   synchronized (methodCache) {
       subscriberMethods = methodCache.get(key);
   }
   if (subscriberMethods != null) {
       return subscriberMethods;
   }
   subscriberMethods = new ArrayList<SubscriberMethod>();
   Class<?> clazz = subscriberClass;
   HashSet<String> eventTypesFound = new HashSet<String>();
   StringBuilder methodKeyBuilder = new StringBuilder();
   while (clazz != null) {
       String name = clazz.getName();
       if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
           // Skip system classes, this just degrades performance
           break;
       }

       // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
       Method[] methods = clazz.getDeclaredMethods();
       for (Method method : methods) {
           String methodName = method.getName();
           if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
               int modifiers = method.getModifiers();
               if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                   Class<?>[] parameterTypes = method.getParameterTypes();
                   if (parameterTypes.length == 1) {
                       String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
                       ThreadMode threadMode;
                       if (modifierString.length() == 0) {
                           threadMode = ThreadMode.PostThread;
                       } else if (modifierString.equals("MainThread")) {
                           threadMode = ThreadMode.MainThread;
                       } else if (modifierString.equals("BackgroundThread")) {
                           threadMode = ThreadMode.BackgroundThread;
                       } else if (modifierString.equals("Async")) {
                           threadMode = ThreadMode.Async;
                       } else {
                           if (skipMethodVerificationForClasses.containsKey(clazz)) {
                               continue;
                           } else {
                               throw new EventBusException("Illegal onEvent method, check for typos: " + method);
                           }
                       }
                       Class<?> eventType = parameterTypes[0];
                       methodKeyBuilder.setLength(0);
                       methodKeyBuilder.append(methodName);
                       methodKeyBuilder.append('>').append(eventType.getName());
                       String methodKey = methodKeyBuilder.toString();
                       if (eventTypesFound.add(methodKey)) {
                           // Only add if not already found in a sub class
                           subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
                       }
                   }
               } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
                   Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
                           + methodName);
               }
           }
       }
       clazz = clazz.getSuperclass();
   }
   if (subscriberMethods.isEmpty()) {
       throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
               + ON_EVENT_METHOD_NAME);
   } else {
       synchronized (methodCache) {
           methodCache.put(key, subscriberMethods);
       }
       return subscriberMethods;
   }
}

四、注意事项

使用EventBus,混淆时需在混淆文件中配置如下:

-keep class de.greenrobot.event.**{*;}
-keepclassmembers class ** {
    public void onEvent*(**);
}

五、和广播比较

广播:

  • 优点:可接收系统级的事件,比如短信发送和接收,网络变化等;在BroadcastReceiver的onReceive方法中,可以获得Context,intent参数,这两个参数可以调用sdk中的方法;支持跨进程通信。
  • 缺点:广播是重量级的,消耗资源较多;使用麻烦,写的代码比较多;只能在主线程接收广播。

EventBus:

  • 优点:使用简单,不依赖于Context,使用时无需像广播一样关注Context的注入与传递;快速轻量;耦合度低;支持主线程/子线程的发送和接收事件。
  • 缺点:不能接收系统级的事件;不能跨进程通信;混淆代码时需注意过滤OnEvent方法的混淆。(3.0支持注解:无需关注混淆配置)

总结:若需要接收系统级的事件或者跨进程通信,建议使用广播;反之,建议使用EventBus。(经过代码实践,对同一事件的接收,广播消耗的资源和消耗的事件均大于EventBus的消耗)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值