随便聊几句EventBus

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 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


你可能感兴趣的:(随便聊几句EventBus)