android平台中,EventBus研究学习

来源:互联网 发布:python问卷系统源码 编辑:程序博客网 时间:2024/06/05 21:13
         当一个Android应用功能越来越多的时候,app中各个部分之间通信,往往采用Observer的方式来进行,即注册----通知----注销的方式执行 各类控件经常需要根据某个状态来更新显示内容。这种场景常见的解决方式就是定义一个接口,需要关注该事件的控件来实现这个接口。 接口类:
      public interface OnChangedListener {
            void onDataChanged();
        }
       被观察者往往以如下形式实现:

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();}@Overridepublic void onDataChanged() {// TODO Auto-generated method stubSystem.out.println("LoginRequest");}}
     使用观察者模式有一个弊病就是部件之间的耦合度太高,所有的主题角色都需要实现同一个interface。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。如果主题角色被注册的observer越多,那么需要实现的interface也就越多,接口方法数量也就越多。
     如何来进行解耦,让代码逻辑更清晰,可读性更强,是一个问题。
     在Android中也有一个类似功能的开源库EventBus,可以很方便的帮助我们实现观察者模式,并且让各个组件之间的耦合性更低。
      关于EventBus的讲解文章,网络业很多,这里推荐一篇,讲解比较详细的blog,http://www.cnblogs.com/angeldevil/p/3715934.html 
对EventBus的认识,最好还是从demo入手,先易后难。首先知道如何使用,然后再深究源码,才能循序渐进,吃透其中的设计理念,便于日后的代码调试和模块重构。关于demo,网上有很多,可以自己去查收。
      EventBus的使用有4个步奏:
1.定义事件类型:
    public class MyEvent
2.注册订阅者:
    EventBus.getDefault().register(this)
3.发送事件:
    EventBus.getDefault().post(new MyEvent())
4.接收事件,处理
     订阅者回调的函数。官方指导,函数名称以onEvent开头。
    在EventBus模块中,有几个重要的概念,了解了这几个概念后,也就不难懂了。
          Event:可以是任意类型的对象
          Subscriber:订阅者,接收特定的
          Publisher:发布者,用于通知Subscriber发送
          EventType:onEvent函数中的参数,表示事件对象,用户自定义的。
          Subscriber:订阅源,即调用register注册的对象,这个对象内包含onEvent成员函数。
SubscribMethod.javafinal 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;... ... ... ... ... ... ... ... ... ... ... ...}
  类EventBus中,有两个核心的成员
   /*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的参数为用户自定义的对象。
       注册时,使用SubscriberMethodFinder的对象,调用到findSubscriberMethods方法,获取到List<SubscriberMethod>。
     数组对象Method[],调用getMethods()方法, 获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。这也是为啥,我们的onEvent函数,要定义为public方法的原因哦。
    在findSubscriberMethods函数中,进行如此频繁的遍历,就是为了找到List<SubscriberMethod>。 每一个订阅者,对应一个List<SubscriberMethod>,有多少onEvent函数,返回的List,就有多少个item。即查找订阅源内的事件处理方法,同时还会查到它的父类中的事件处理方法,返回list,交给
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的接口方法的多次、频繁的定义。


0 0
原创粉丝点击