EventBus优点
1、简化组件间的交互
解耦事件发送者和接收者
与Activities, Fragments, 和 后台线程之间使用 表现的好
避免复杂和易错的库和生命周期问题
2、让你的代码更简洁
3、是快速的
4、文件极小(jar包大概60k)
5、有先进的特色像传递线程、订阅者优先级等
6、在实际使用中APP安装超过10亿次
这些特点是它们官方写的,我们现在使用一个例子来看一下,它的使用。
使用例子
这里使用一个Activity和一个Fragment来举例子,简单看一下,EventBus是怎么使用的。
下面是MainActivity的代码:
public class MainActivity extends FragmentActivity {
public static final String TAG = "MainActivity";
private TextView main_tv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_ac);
main_tv = findViewById(R.id.main_tv);
FragmentManager fmanager = getSupportFragmentManager();
FragmentTransaction trac = fmanager.beginTransaction();
trac.add(R.id.main_fl, new BusFragment());
trac.commit();
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent met) {
main_tv.setText(met.toString());
Log.e(TAG, "onMessageEvent接收到消息:" + met);
}
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
里面主要是有个文本控件TextView main_tv,添加了一个BusFragment。
它在onCreate()中执行了注册订阅者,这里的订阅者就是MainActivity 。在onDestroy()中执行取消注册。
同时它还使用@Subscribe注解,来声明接收方法和事件。
事件是用类来定义的,这里就是MessageEvent
public class MessageEvent {
int count;
String con;
@Override
public String toString() {
return "MessageEvent{" +
"count=" + count +
", con='" + con + '\'' +
'}';
}
}
事件类里有两个变量count和con。
再看看BusFragment里面的代码:
public class BusFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bus_frag, container, false);
Button frag_btn = view.findViewById(R.id.frag_btn);
frag_btn.setOnClickListener(itview ->{
MessageEvent et = new MessageEvent();
et.count = 10;
et.con = "测试内容";
EventBus.getDefault().post(et);
});
return view;
}
}
BusFragment里面有个按钮frag_btn ,点击之后,会将事件类赋值,然后调用EventBus.getDefault().post(et)发布事件。
这样就能向MainActivity中发布事件,MainActivity就能在它的onMessageEvent()中接到事件消息了。
这样就能实现Activity与Fragment交互了。通过代码来看,是比较简洁。
源代码分析
下面就从注册订阅者,发布事件,取消注册订阅者三个方面来分析。
注册订阅者
调用的是EventBus.getDefault().register(this),在这里this是MainActivity,它是订阅者。
先是调用EventBus.getDefault()生成一个默认EventBus对象,然后才是调用注册订阅者register(this)。
生成一个默认EventBus对象
EventBus的成员变量,拣几个重要的说一下,如下:
stickyEvents:则为粘性事件相关的,key为粘性事件类的Class,值则为粘性事件类对象。
mainThreadSupport:用来判断当前执行的线程是不是在主线程中
mainThreadPoster:主要用来处理threadMode为MAIN或MAIN_ORDERED的订阅方法的执行,将它们放到主线程中去执行。
backgroundPoster:主要用来处理threadMode为BACKGROUND的订阅方法的执行,要执行订阅方法的时候,如果发现是在主线程,backgroundPoster会将订阅方法是现在后台线程中执行。
asyncPoster:主要用来处理threadMode为ASYNC的订阅方法的执行,这里主要强调的是异步,就是在要执行订阅方法的时候,是要启动新线程去执行该方法。
subscriberMethodFinder:顾名思义,订阅方法的查找者。没错就是在该类中找到的订阅方法。后面详细说明。
executorService:线程池,它默认为Executors.newCachedThreadPool()。
throwSubscriberException:默认为false。如果执行订阅方法时,出现异常,是否会抛出异常。
sendSubscriberExceptionEvent:默认为true。如果执行订阅方法时,出现异常,是否发送SubscriberExceptionEvent事件。
sendNoSubscriberEvent:默认为true。在发布事件时,如果没找到对应的订阅方法执行,是否会发布NoSubscriberEvent事件。
eventInheritance:在发布事件的时候,不止会发布它本身类型,还会发布它继承的所有接口、类 事件类型。默认为true;如果在订阅粘性事件时,却是会找到它本身和它的子类的事件,进行发布。
EventBus的构造使用的是建造者模式,使用的是EventBusBuilder。看一下EventBus.getDefault():
static volatile EventBus defaultInstance;
…………
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;
}
典型的单例生成双检查,因为最开始defaultInstance为null,所以会走到EventBus的初始化函数
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
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);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
DEFAULT_BUILDER 是EventBus类的静态变量,我们看到,这里没有使用构造着经典的build()方法,而是采用的赋值方式来生成EventBus对象。其中各个变量,在上面介绍类对象成员变量时,都说了。
注册订阅者
看一下EventBus的register(Object subscriber)方法:
public void register(Object subscriber) {
if (AndroidDependenciesDetector.isAndroidSDKAvailable() && !AndroidDependenciesDetector.areAndroidComponentsAvailable()) {
// Crash if the user (developer) has not imported the Android compatibility library.
throw new RuntimeException("It looks like you are using EventBus on Android, " +
"make sure to add the \"eventbus\" Android library to your dependencies.");
}
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
参数subscriber是订阅者,在上面的例子里,是MainActivity实例。
先得到subscriber的Class,然后调用EventBus的成员变量subscriberMethodFinder的findSubscriberMethods(),得到对应Class上面的订阅方法(@Subscribe标注的方法)。
再循环调用subscribe(subscriber, subscriberMethod)方法将subscriber订阅subscriberMethod。实际就是将subscriber和subscriberMethod放到相应数据结构(主要是subscriptionsByEventType和typesBySubscriber)中,等待订阅事件发布时,去相关数据结构中拿到相关信息执行订阅方法。
得到订阅者实现的订阅方法
它主要是调用subscriberMethodFinder.findSubscriberMethods(subscriberClass)得到。subscriberMethodFinder是SubscriberMethodFinder类对象,参数subscriberClass是上面得到的订阅者的Class。它的代码执行方法如下:
现在看一下具体的SubscriberMethodFinder类的findSubscriberMethods()方法:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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 {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
参数subscriberClass是订阅者对象的Class,订阅者对象上允许生命多个订阅方法,所以查找出来的结果是集合List。METHOD_CACHE是ConcurrentHashMap<Class<?>, List>对象,它是用作缓存使用的,如果之前查找过,就将结果存储起来,key值就是订阅者对象的Class。所以如果从缓存中查询出来之后,就拿到对应的结果不为null,就直接返回了。
ignoreGeneratedIndex默认为false,所以调用findUsingInfo(subscriberClass)得到结果。
最后会将结果放入METHOD_CACHE中。
我们再看findUsingInfo(subscriberClass)之前,需要先了解一下FindState 类结构如下:
anyMethodByEventType:是用来在查找过程中做判断用的,key是事件类型的Class,value则是Method或者FindState类对象。
subscriberClassByMethodKey也是用来在查找过程中做判断用的,key是方法名称 + “>” + 事件类型名,value是方法的生命类的Class(订阅类的Class)。
methodKeyBuilder:是用来拼subscriberClassByMethodKey的key值
subscriberClass:订阅者类的Class
clazz:刚开始订阅者类的Class,后面会向它的父类Class递归
skipSuperClasses:是否跳过父类的Class里面方法的查找
subscriberInfo:订阅者信息,目前一直为null
FindState类还使用缓存机制。它的实现是SubscriberMethodFinder的FIND_STATE_POOL。它是一个FindState数组,大小为4。
现在可以继续看findUsingInfo()的方法了。
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
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 {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
prepareFindState()方法就是先取FIND_STATE_POOL中的对象,如果没有,会重新生成一个。
findState.initForSubscriber(subscriberClass)就是将findState的subscriberClass和clazz设置为订阅者的Class。skipSuperClasses为false,subscriberInfo为null。
下面会进入一个while循环,因为findState.subscriberInfo为null,所以对当前findState.clazz不为null进行处理findUsingReflectionInSingleClass()完之后,会向它的父类Class遍历,继续执行。转向父类Class是通过findState.moveToSuperclass()实现的。
最后会调用getMethodsAndRelease(findState)得到findState对象成员subscriberMethods里面存储的结果,并且将findState放入缓存池FIND_STATE_POOL中。
这里最主要的处理还是findUsingReflectionInSingleClass(findState)。看完它,我们就能知道EventBus是怎么通过反射来实现的查找订阅方法了。
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
try {
methods = findState.clazz.getMethods();
} catch (LinkageError error) {
// super class of NoClassDefFoundError to be a bit more broad...
String msg = "Could not inspect methods of " + findState.clazz.getName();
if (ignoreGeneratedIndex) {
msg += ". Please consider using EventBus annotation processor to avoid reflection.";
} else {
msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
}
throw new EventBusException(msg, error);
}
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) {
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)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
目前findState.clazz是订阅者的Class,也就对应着上述例子中的MainActivity的Class。通过反射机制,调用它的getDeclaredMethods()方法,得到自己类声明的所有方法。如果该方法发生异常,会调用getMethods(),注意getMethods()会返回包含的从超类和超接口继承的public方法,并且会将skipSuperClasses设置为true。因为已经得到了所有的方法,不用再向父类遍历。
接着对查询到的Method,进行循环。
首先判断方法的修饰符,可见订阅方法需要设置成public。并且不能带一下四种修饰符,Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC。Modifier.ABSTRACT | Modifier.STATIC这俩我们知道,抽象方法或静态方法。BRIDGE | SYNTHETIC则是在以具体类型继承自一个泛型类,同时被继承的泛型类包含了泛型方法,则该方法会带BRIDGE | SYNTHETIC标识。在这里我们需要知道这种类上的对应方法声明订阅方法不起作用。
订阅方法的参数只能为一个,并且需要有Subscribe注解。strictMethodVerification默认为false,如果设置为true,则会报异常EventBusException。
eventType是方法参数的Class,也就是订阅事件类的Class。会通过findState.checkAdd(method, eventType)来判断是否能将方法和相关信息添加到findState.subscriberMethods中。SubscriberMethod类就是来描述订阅方法的。它的成员包括执行方法Method,事件类型还有通过注解Subscribe得到的threadMode,priority、sticky。
下面看一下findState.checkAdd(method, eventType),看一下什么情况下,能添加方法。
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
可以看到每次添加新事件类型的时候,肯定是可以添加进去的。因为anyMethodByEventType里面对应的key对应的值为null。
如果第二次添加同类型的事件呢?分两种情况,就是Method方法名称是否和之前添加的相同。还发现,第二次添加同种事件类型时,会执行两遍checkAddWithMethodSignature()方法。分两种情况讨论一下
1、方法名和之前不同
会通过anyMethodByEventType.put(eventType, method)得到之前添加的Method,因为它为Method,所以会进入第一次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();
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
看到了吧,会拼凑key值为fangfaming + “>” + 事件类名作为key值。拿到声明方法的Class,添加到subscriberClassByMethodKey中,第一次添加这个key值,所以得到的methodClassOld为null,直接返回true。这里要想清楚的一点时,method是第一次添加事件时候的那个方法。
checkAddWithMethodSignature()第一遍执行返回true,之后,会将anyMethodByEventType里的值更新为FindState类对象。接着会走第二遍。这次method为要添加的方法,再次走到checkAddWithMethodSignature()方法里面,因为方法名字不同,所以生成key值,在subscriberClassByMethodKey还是没有对应的值,添加之后,methodClassOld 仍然为null,所以返回true。
这个时候,是可以将订阅方法添加到结果中。
2、方法名和之前相同
这次和第一种情况不同的是在第二遍执行checkAddWithMethodSignature()的时候,第一遍执行的情况是一样的。
第二遍checkAddWithMethodSignature生成key的值,由于方法名和事件名都一样,所以subscriberClassByMethodKey.put()的时候,返回的结果不为null了。它是第一次添加方法时方法的声明类。然后做methodClassOld.isAssignableFrom(methodClass)判断,methodClassOld为第一次添加方法时方法的声明类。methodClass为第二次添加方法的声明类。
methodClassOld.isAssignableFrom(methodClass),是做判断methodClassOld是methodClass的父类、接口类或者相等的时候,会返回true。也就是第一次添加这种事件类型的类是第二种添加类型的类的父类、接口类或者相等的时候,会返回true。
我们再思考一下,什么情况下,会添加方法名和事件类型都相同的订阅方法。同一个类中肯定不行,那只有在子类和父类中都定义了相同事件的方法名也一样的函数。通过findUsingInfo(),我们知道,是先从子类添加事件的,所以第一次添加这种事件类型的类是第二种添加类型的类的子类,遍历到父类添加方法时,肯定通过不了。所以我们知道FindState类的成员subscriberClassByMethodKey主要就是为了防止这种情况的。
这样回到register(Object subscriber)方法里subscriberMethodFinder.findSubscriberMethods(subscriberClass)执行完毕,查找的结果都在subscriberMethods中了。
订阅者订阅方法
看一下对应的subscribe()方法代码,代码有点长,分段来看:
// Must be called in synchronized block
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<>();
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;
}
}
它主要将订阅者,订阅对象封装到Subscription中,然后将它放入subscriptionsByEventType中。
先生成Subscription对象newSubscription,它包含订阅者subscriber和订阅方法subscriberMethod。subscriptionsByEventType是以订阅事件的类型为key,如果为空,会新建一个并且,将新建的放进subscriptionsByEventType中。
接着会根据优先级的大小来找位置。优先级越大,位置越靠前。
再看一下subscribe()方法的第二段代码:
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
这段代码挺简单,将订阅者订阅的事件类型放入typesBySubscriber中。
再来看subscribe()方法的最后一段代码
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
如果当前订阅方法是sticky,则会检查stickyEvents中的事件,如果他们是当前订阅方法事件类型的子类或同类,则会发布其中的事件。这就会实现,粘性事件发布之后,然后再订阅也是可以收到对应事件的。
前面解释过eventInheritance,也解释过isAssignableFrom()方法。这里就是遍历stickyEvents里的事件,如果事件类型和当前绑定的eventType相同,或者是它的子类,就会调用checkPostStickyEventToSubscription(newSubscription, stickyEvent),执行发布。看一下它:
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
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, isMainThread());
}
}
粘性事件不为null,就去执行postToSubscription(newSubscription, stickyEvent, isMainThread()),执行发布,发布的内容在下面讲。
发布事件
发布事件是调用的EventBus.getDefault().post(Object event):
/** Posts the given event to the event bus. */
public void post(Object event) {
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;
}
}
}
currentPostingThreadState是和线程相关的,调用get()会得到一个PostingThreadState类。它的成员eventQueue是ArrayList类型,用作事件队列。这里将事件放到队列中。
postingState.isPosting代表是否正在发送事件。postingState.isPosting为false,下面就开始发送消息,然后接着就将postingState.isPosting为true。postingState.isMainThread被赋值为isMainThread(),代表当前线程是不是主线程。
接着开启循环调用postSingleEvent(),将队列里里的事件发送。最后再将postingState.isPosting = false,postingState.isMainThread = false。
是否在主线程中
看一下isMainThread(),看它是怎么确定主线程的
private boolean isMainThread() {
return mainThreadSupport == null || mainThreadSupport.isMainThread();
}
如果mainThreadSupport 为null或者mainThreadSupport.isMainThread()。这里mainThreadSupport是在EventBusBuilder中定义的,看一下
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (AndroidComponents.areAvailable()) {
return AndroidComponents.get().defaultMainThreadSupport;
} else {
return null;
}
}
可以看到主要是通过AndroidComponents.get().defaultMainThreadSupport得到的,AndroidComponents.get()为:
private static final AndroidComponents implementation;
static {
implementation = AndroidDependenciesDetector.isAndroidSDKAvailable()
? AndroidDependenciesDetector.instantiateAndroidComponents()
: null;
}
public static boolean areAvailable() {
return implementation != null;
}
public static AndroidComponents get() {
return implementation;
}
public final Logger logger;
public final MainThreadSupport defaultMainThreadSupport;
public AndroidComponents(Logger logger, MainThreadSupport defaultMainThreadSupport) {
this.logger = logger;
this.defaultMainThreadSupport = defaultMainThreadSupport;
}
可以看到implementation是由AndroidDependenciesDetector.instantiateAndroidComponents()得到:
private static final String ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME = "org.greenrobot.eventbus.android.AndroidComponentsImpl";
public static AndroidComponents instantiateAndroidComponents() {
try {
Class<?> impl = Class.forName(ANDROID_COMPONENTS_IMPLEMENTATION_CLASS_NAME);
return (AndroidComponents) impl.getConstructor().newInstance();
}
catch (Throwable ex) {
return null;
}
}
可见,真正初始化的是AndroidComponentsImpl类
public class AndroidComponentsImpl extends AndroidComponents {
public AndroidComponentsImpl() {
super(new AndroidLogger("EventBus"), new DefaultAndroidMainThreadSupport());
}
}
可以看到它的defaultMainThreadSupport 为DefaultAndroidMainThreadSupport类对象。
所以EventBus对象的mainThreadSupport为DefaultAndroidMainThreadSupport类对象。
看一下它的isMainThread()
@Override
public boolean isMainThread() {
return Looper.getMainLooper() == Looper.myLooper();
}
判断当前线程的Looper是否等于主线程的Looper.getMainLooper(),如果相等,就是在主线程中,如果不等,就不再主线程。
发布单个事件
看一下postSingleEvent(Object event, PostingThreadState postingState)的相关代码:
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) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
eventClass 事件的类型Class,subscriptionFound 代表是否发布了事件。在这里可以看到eventInheritance的作用,是调用了lookupAllEventTypes(eventClass)找到了它的本身类的Class,还有它继承的父类和接口的相关Class。只要找到这些匹配的事件对象都会调用。
接着对所有找到的事件类型,都调用postSingleEventForEventType(event, postingState, clazz)进行执行。看一下它的代码:
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;
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;
}
它从subscriptionsByEventType里面得到需要执行的订阅方法的信息。如果找到了,遍历subscriptions,拿到subscription,继续调用postToSubscription(subscription, event, postingState.isMainThread)执行发送消息。
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);
}
}
这里就开始处理订阅方法。在处理之前,还需要看看是否要产生线程调度。例如,这里配置的threadMode为MAIN,就是要求需要在主线程中执行,前面我们已经判断调用的线程是否在主线程中,现在由变量isMainThread控制。如果isMainThread为true,直接就调用invokeSubscriber(subscription, event),如果isMainThread为false,则调用mainThreadPoster.enqueue(subscription, event)。
线程调度
咱们就选择配置为主线程的调用的来讲讲它是怎么实现执行调度的。
首先,如果目前就在主线程中,不产生线程调度,直接执行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);
}
}
直接就调用Method的invoke方法实现方法执行。subscription.subscriber就是订阅者对象,event就是事件,subscription.subscriberMethod.method就是订阅方法。
再看看目前不在主线程中,调用mainThreadPoster.enqueue(subscription, event)。mainThreadPoster是mainThreadSupport.createPoster(this)生成的,前面我们知道mainThreadSupport是DefaultAndroidMainThreadSupport类对象。看一下DefaultAndroidMainThreadSupportd的createPoster(this)
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, Looper.getMainLooper(), 10);
}
所以mainThreadPoster是HandlerPoster对象。看一下HandlerPoster的enqueue(subscription, event)
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");
}
}
}
}
HandlerPoster是继承了Handler类的,它在将调用信息和事件封装成一个PendingPost 对象之后,放到queue里。然后它在这里调用sendMessage(obtainMessage())发送消息,通过Android的消息传递机制,实现线程调度。
再看看HandlerPoster的handleMessage(Message msg):
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
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;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
可以看到,从队列里面拿到PendingPost对象,接着调用eventBus.invokeSubscriber(pendingPost)去执行。
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);
}
}
判断一下Subscription 对象的active为true,代表它是活跃状态,然后才去执行它的订阅方法。最终也是执行了Method的invoke(),执行了订阅方法的调用。
其他线程模式的切换,都是调用了EventBus对象的线程池实现的,这里不细说了。
取消注册订阅者
取消订阅者,就是你不想要订阅这个事件了,这个时候,需要执行EventBus.getDefault().unregister(this)方法。看下它的代码:
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
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--;
}
}
}
}
主要是处理typesBySubscriber和subscriptionsByEventType。
通过typesBySubscriber得到订阅者都订阅了哪些类型的事件,然后遍历所有事件类型,再调用unsubscribeByEventType(subscriber, eventType)去处理subscriptionsByEventType里的订阅事件信息。遍历完成后,typesBySubscriber会将该订阅者去除。
unsubscribeByEventType(subscriber, eventType)也是找到里面符合取消订阅者的订阅信息类Subscription 。将它subscription.active = false,删除掉。
总结
分析完整个框架代码,我们知道EventBus是通过反射来实现订阅方法的注册、订阅方法的执行。通过注解能设置订阅方法的线程调度、优先级、粘性事件。确实使用起来比较简单,代码看起来也比较简洁。它在自己内部实现了线程调度,用户只需设置订阅方法的线程调度模式即可。
思考
思考:反射机制是会影响程序的性能的,如果订阅者对象类是一个方法很多的类,包括它的父类的方法很多,应该都会产生影响。像前面的那个例子,MainActivity是继承的FragmentActivity,FragmentActivity又继承了其他类,难道这些都需要遍历吗?
我们把查找订阅对象的方法再拿出来看一下:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
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 {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
这个循环在findState.clazz为null的时候,会停止。查询完当前MainActivity的Class之后,会走findState.moveToSuperclass(),看一下,它怎么找父类的:
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
// Skip system classes, this degrades performance.
// Also we might avoid some ClassNotFoundException (see FAQ for background).
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") ||
clazzName.startsWith("android.") || clazzName.startsWith("androidx.")) {
clazz = null;
}
}
}
看到了吧,如果父类是以"java."“javax.”、“android.”、"androidx."开头的包名,那就认为找到了系统提供的类了。我们一般也不会自己定义该种包开头的类,像例子中的父类FragmentActivity,完整带报名androidx.fragment.app.FragmentActivity,所以,就会将clazz设置为null。直接就跳出循环了。
行了,该篇文章到这结束了。