android平台中,EventBus研究学习
被观察者往往以如下形式实现:
public abstract class AbsHTTPRequest { private final WeakHashMap<OnChangedListener, Boolean> mListeners = new WeakHashMap<OnChangedListener, Boolean>(); public interface OnChangedListener { void onDataChanged(); } /*HTTP's response*/ public abstract void onResponse(); public final void addListener(OnChangedListener listener) { mListeners.put(listener, true); } public final void removeListener(OnChangedListener listener) { mListeners.remove(listener); } protected final void notifyDataChanged() { Set<OnChangedListener> keys = mListeners.keySet(); if(keys != null) { Iterator<OnChangedListener> iterator = keys.iterator(); while(iterator.hasNext()) { iterator.next().onDataChanged(); } } } }具体的主题角色( 被观察者),实现方式如下:
public class LoginRequest extends AbsHTTPRequest implements OnChangedListener{ public void onResponse(){ addListener(this); notifyDataChanged(); } @Override public void onDataChanged() { // TODO Auto-generated method stub System.out.println("LoginRequest"); } }使用观察者模式有一个弊病就是部件之间的耦合度太高,所有的主题角色都需要实现同一个interface。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。如果主题角色被注册的observer越多,那么需要实现的interface也就越多,接口方法数量也就越多。
如何来进行解耦,让代码逻辑更清晰,可读性更强,是一个问题。
在Android中也有一个类似功能的开源库EventBus,可以很方便的帮助我们实现观察者模式,并且让各个组件之间的耦合性更低。
SubscribMethod.java final class SubscriberMethod { final Method method; /*Method类型的method成员表示这个onEvent,即事件处理函数。同时也包含订阅源*/ final ThreadMode threadMode; final Class<?> eventType; /*事件的对象,用户自定义Object*/ ... ... ... ... ... ... ... ... ... ... ... ... }Subscription.java
final class Subscription { final Object subscriber; /*订阅源Subscriber,即调用register注册的对象*/ final SubscriberMethod subscriberMethod; /**/ final int priority; ... ... ... ... ... ... ... ... ... ... ... ... }
/*EventType -> List<Subscription>,事件到订阅对象之间的映射*/ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; /* Subscriber -> List<EventType>,订阅对象到它订阅的的所有事件的映射关系*/ private final Map<Object, List<Class<?>>> typesBySubscriber;注册流程:在调用register函数时,EventBus类有多个重载的register函数,但是作者更倾向于使用register(this);含有 多个参数的register函数中,明确标注了@deprecated,原创作者不建议使用。从代码:
public void register(Object subscriber) { register(subscriber, DEFAULT_METHOD_NAME, false, 0); }可以观察到,所有重载的register函数,都调用到了
private synchronized void register(Object subscriber, String methodName, boolean sticky, int priority) { List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(),methodName); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } }其中注册函数register,默认参数DEFAULT_METHOD_NAME为函数名称"onEvent",在java放射机制中,所有的事件处理函数名称 统一为“onEvent”,仅仅参数不一致。onEvent的参数为用户自定义的对象。
数组对象Method[],调用getMethods()方法, 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。这也是为啥,我们的onEvent函数,要定义为public方法的原因哦。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority)进行处理。
Event与Subscriber之间,是一对多的关系。即一个事件,可以被多个订阅者关注。
Subscriber与Event之间,也是一对多的关系。即一个订阅者,可以订阅多个事件。
subscribe方法,也就是将上述的那样的关系,进行理顺,合理的建立map的映射关系,主要做了这样几件事件。
a.根据SubscriberMethod中的EventType类型,将Subscribtion对象存放在subscriptionsByEventType中。建立EventType与Subscription的映射,一个事件可以有多个订阅者。
b.根据Subscriber将EventType存放在typesBySubscriber`中,建立Subscriber到EventType的映射,每个Subscriber可以订阅多个事件。
c.如果是Sticky类型的订阅者,直接向它发送上个保存的事件(如果有的话)。
通过Subscriber到EventType的映射,我们就可以很方便地使一个Subscriber取消接收事件,通过EventType到Sucscribtion的映射,可以方便地将相应的事件发送到它的每一个订阅者。
与Observer不同的是,使用EventBus,不同的被观察者,不需统一实现Observer中的interface方法,在上层代码中,也不需要逐一进行notify机制。通过Map进行订阅源与事件函数的对应关系,进行解耦,为其核心之处。
发送流程:
EventBus.getDefault().post(new EventType());参数为用户自定义的对象。最为简单的处理方式,实现事件发送。
当事件发送出去后,所有的订阅者,是如何调用其事件方法的呢?这个就需要遍历上文提到的subscriptionsByEventType的Map了。Post发送事件,入口为post函数:public void post(Object event),在postSingleEvent函数中个,有一个重要的处理函数:
/** Finds all Class objects including super classes and interfaces. */ private List<Class<?>> findEventTypes(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; } }其作用,就是把这个事件类的对象、实现的接口及父类的类对象存到一个List中返回,根据list中的eventTypes,遍历subscriptionsByEventType,获取订阅源对象,进行逐一的调用事件函数。
这里需要注意的是,当Post一个事件时,这个事件的父事件(事件类的父类事件)、接口事件也会被Post,所以如果订阅者接收Object类型的事件,即包含onEvent(Object object)事件函数,那么Subscriber就可以接收所有的事件。
通过本篇博文的了解,EventBus就是通过Map,建立订阅源与事件函数的对应关系,进行解耦,来规避Observer的接口方法的多次、频繁的定义。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。