EventBus(github地址
https://github.com/greenrobot/EventBus),是一个消息分发总线开源框架,可以方便地在android应用的不同组件之间进行消息通信。最近接手一个使用了EventBus的android app项目,随便聊几句EventBus。
第一,消息总线的出现更加弱化了主Service。
目前android第三方app开发越来越借助于各种第三方库,甚至说是由第三方库堆砌而成也不为过。从这个角度看,android第三方app开发越来越像服务器开发了。android第三方app开发已经与android Rom系统app开发越来越不同。
Service是android应用四大组件之一,用于处理无UI交互的应用逻辑,以及向另一个应用提供功能接口。以往,对于一个app而言,一般需要一个主Service来统领全局通信(各应用组件之间)。Service的另一个重要作用是当app在后台时,提升app process在低内存情况下,存活的几率,Service等于向android os通告自己在做重要的事情,不能够轻易杀死进程以释放内存。
EventBus的出现,统领全局通信的功能就可以从主Service完全移交给EventBus。提高后台存活率的主要功能是保持长链接或者push通道的存活。现在这些后台功能大量使用第三方库,Service往往封装在第三方库中,只要在AndroidManifest中添加对应的Service即可。所以主Service可能将慢慢退出历史舞台了。
第二,EventBus的内部实现初探。
简单跟了一下EventBus的注册(或者叫订阅)流程,发现EventBus是使用反射(而不是实现回调接口)的方式来减少使用成本。代码如下:
使用方注册:
EventBus.getDefault().register(this);
EventBus.getDefault()使用单例模式保证全局唯一总线:
public static EventBus getDefault() {
if(defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if(defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
注册流程:
EventBus:
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
Iterator i$ = subscriberMethods.iterator();
while(i$.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)i$.next();
this.subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class eventType = subscriberMethod.eventType;
CopyOnWriteArrayList subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
if(subscriptions == null) {
subscriptions = new CopyOnWriteArrayList();
this.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 subscribedEvents = 0; subscribedEvents <= size; ++subscribedEvents) {
if(subscribedEvents == size || newSubscription.priority > ((Subscription)subscriptions.get(subscribedEvents)).priority) {
subscriptions.add(subscribedEvents, newSubscription);
break;
}
}
Object var15 = (List)this.typesBySubscriber.get(subscriber);
if(var15 == null) {
var15 = new ArrayList();
this.typesBySubscriber.put(subscriber, var15);
}
((List)var15).add(eventType);
if(sticky) {
if(this.eventInheritance) {
Set stickyEvent = this.stickyEvents.entrySet();
Iterator i$ = stickyEvent.iterator();
while(i$.hasNext()) {
Entry entry = (Entry)i$.next();
Class candidateEventType = (Class)entry.getKey();
if(eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent1 = entry.getValue();
this.checkPostStickyEventToSubscription(newSubscription, stickyEvent1);
}
}
} else {
Object var16 = this.stickyEvents.get(eventType);
this.checkPostStickyEventToSubscription(newSubscription, var16);
}
}
}
SubscriberMethodFinder.findSubscriberMethods():
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
Map clazz = methodCache;
List subscriberMethods;
synchronized(methodCache) {
subscriberMethods = (List)methodCache.get(subscriberClass);
}
if(subscriberMethods != null) {
return subscriberMethods;
} else {
ArrayList subscriberMethods1 = new ArrayList();
Class clazz1 = subscriberClass;
HashMap eventTypesFound = new HashMap();
for(StringBuilder methodKeyBuilder = new StringBuilder(); clazz1 != null; clazz1 = clazz1.getSuperclass()) {
String name = clazz1.getName();
if(name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
break;
}
try {
Method[] th = clazz1.getDeclaredMethods();
this.filterSubscriberMethods(subscriberMethods1, eventTypesFound, methodKeyBuilder, th);
} catch (Throwable var12) {
Method[] methods = subscriberClass.getMethods();
subscriberMethods1.clear();
eventTypesFound.clear();
this.filterSubscriberMethods(subscriberMethods1, eventTypesFound, methodKeyBuilder, methods);
break;
}
}
if(subscriberMethods1.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " + "onEvent");
} else {
Map name1 = methodCache;
synchronized(methodCache) {
methodCache.put(subscriberClass, subscriberMethods1);
return subscriberMethods1;
}
}
}
}
从这几段代码可以大概看出,一个对象在EventBus调用接口注册,EventBus会使用反射抓出这个对象对应的类的以“onEvent”开头的方法,这些方法会作为这个对象的注册信息,被EventBus所保存。在分发Event(消息)的时候,应该是直接去利用反射调用这些对象的这些方法即可(这里没有去看具体的code)。
这样,在使用EventBus的客户类中,就没有任何的痕迹了(譬如,实现一个回调接口),耦合性降低。当然,这种方式需要使用EventBus的类的“onEventxxx”方法不能被混淆。另外,因为这些类的“onEventxxx”方法没有被显式调用,也要注意不能被某些编译工具的dex优化逻辑删除掉,譬如Dexguard,详见另一篇:
http://blog.csdn.net/zhanglianyu00/article/details/51750825
。