1. 程式人生 > >Guava中EventBus的使用和詳解

Guava中EventBus的使用和詳解

概述

        EventBus是Google Guava庫中一個常用的元件。他使用了設計模式中的Observer(觀察者)模式,實現了一個publish/subscribe模型的訊息匯流排,簡化了各元件之間之間的通訊。         Observer模式是比較常見和簡單的設計模式之一,在JDK中,提供Observable和Observer這兩個類可以快速使用。EventBus是Google在Guava中所實現的一個更加優雅和間的方案。更為重要的是,利用EventBus可以將事件釋出者和事件訂閱者解耦。釋出者不再需要知道有那些訂閱者,事件的派發由EventBus完成。

EventBus的基本用法:

        在傳統的Android程式開發中,實現Observer模式往往會為被觀察物件定義一個Listener介面,而觀察者實現一個繼承此介面的物件作為Listener並註冊給被觀察物件。而使用Guava中的EventBus後,如果想訂閱訊息,並不需要再去繼承Observable所指定的介面。之需要在制定的方法中加上@Subscribe註解即可。        觀察者:
import com.google.common.eventbus.EventBus;


public class TestObserver {

	private EventBus = new Event("TestEventBus");
	EventBus.register(this);

	private TestObservable mObservable;

	@Subscribe
	public void onTestEvent(TestEvent event) {
		// implement event handling here
	}

}
    被觀察者:
public class TestObservable {

	private EventBus mEventBus;

	public void setEventBus(EventBus event_bus) {
		mEventBus = event_bus;
	}

	public void postSomeEvent() {
		if (mEventBus != null) {
			mEventBus.post(new TestEvent());
		}
	}
}
    訊息定義:
public class TestEvent{
}
     可以看出,使用EventBus主要有以下步驟:
  1. 自定義一個訊息型別
  2. 建立一個EventBus,並將觀察者註冊在這個EventBus中,並實現處理此訊息型別的函式,以註解@Subscribe修飾。
  3. 被觀察者獲得EventBus物件,當需要釋出訊息的時候,向此EventBus物件釋出Event。觀察者便會對應的訊息處理函式中收到此訊息。

EventBus的程式碼分析

Register函式

        首先來分析EventBus類中的register函式:
  public void register(Object object) {
    Multimap<Class<?>, EventSubscriber> methodsInListener =
        finder.findAllSubscribers(object);
    subscribersByTypeLock.writeLock().lock();
    try {
      subscribersByType.putAll(methodsInListener);
    } finally {
      subscribersByTypeLock.writeLock().unlock();
    }
  }
methodsInListener中會根據@Subscribe的註解查詢所傳入物件的EventHandler,並將事件型別與EventSubscriber的對映保留在subscribersByType物件中。 再來看AnnotatedSubscriberFinder中的findAllSubscribers方法:
  @Override
  public Multimap<Class<?>, EventSubscriber> findAllSubscribers(Object listener) {
    Multimap<Class<?>, EventSubscriber> methodsInListener = HashMultimap.create();
    Class<?> clazz = listener.getClass();
    for (Method method : getAnnotatedMethods(clazz)) {
      Class<?>[] parameterTypes = method.getParameterTypes();
      Class<?> eventType = parameterTypes[0];
      EventSubscriber subscriber = makeSubscriber(listener, method);
      methodsInListener.put(eventType, subscriber);
    }
    return methodsInListener;
  }
上面程式碼的內容就是通過反射讀取Subscriber物件中帶有@Subscribe註解的方法,並使用makeSubscriber將Subscriber物件和它的帶@Subscribe物件的method物件封裝成EventSubscriber標準事件處理物件:
  private static EventSubscriber makeSubscriber(Object listener, Method method) {
    EventSubscriber wrapper;
    if (methodIsDeclaredThreadSafe(method)) {
      wrapper = new EventSubscriber(listener, method);
    } else {
      wrapper = new SynchronizedEventSubscriber(listener, method);
    }
    return wrapper;
  }

Post函式:

  public void post(Object event) {
    Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());

    boolean dispatched = false;
    for (Class<?> eventType : dispatchTypes) {
      subscribersByTypeLock.readLock().lock();
      try {
        Set<EventSubscriber> wrappers = subscribersByType.get(eventType);

        if (!wrappers.isEmpty()) {
          dispatched = true;
          for (EventSubscriber wrapper : wrappers) {
            enqueueEvent(event, wrapper);
          }
        }
      } finally {
        subscribersByTypeLock.readLock().unlock();
      }
    }

    if (!dispatched && !(event instanceof DeadEvent)) {
      post(new DeadEvent(this, event));
    }

    dispatchQueuedEvents();
  }

首先獲取事件型別,再將事件和對應的EventSubscriber加入佇列:
  void enqueueEvent(Object event, EventSubscriber subscriber) {
    eventsToDispatch.get().offer(new EventWithSubscriber(event, subscriber));
  }
最後通過dispatchQueuedEvents()處理佇列中的事件:
  void dispatchQueuedEvents() {
    // don't dispatch if we're already dispatching, that would allow reentrancy
    // and out-of-order events. Instead, leave the events to be dispatched
    // after the in-progress dispatch is complete.
    if (isDispatching.get()) {
      return;
    }

    isDispatching.set(true);
    try {
      Queue<EventWithSubscriber> events = eventsToDispatch.get();
      EventWithSubscriber eventWithSubscriber;
      while ((eventWithSubscriber = events.poll()) != null) {
        dispatch(eventWithSubscriber.event, eventWithSubscriber.subscriber);
      }
    } finally {
      isDispatching.remove();
      eventsToDispatch.remove();
    }
  }
dispatch的程式碼如下:
  void dispatch(Object event, EventSubscriber wrapper) {
    try {
      wrapper.handleEvent(event);
    } catch (InvocationTargetException e) {
      try {
        subscriberExceptionHandler.handleException(
            e.getCause(),
            new SubscriberExceptionContext(
                this,
                event,
                wrapper.getSubscriber(),
                wrapper.getMethod()));
      } catch (Throwable t) {
        // If the exception handler throws, log it. There isn't much else to do!
        Logger.getLogger(EventBus.class.getName()).log(Level.SEVERE,
             String.format(
            "Exception %s thrown while handling exception: %s", t,
            e.getCause()),
            t);
      }
    }
  }
wrapper.hanleEvent()反射呼叫事件處理的方法:
  public void handleEvent(Object event) throws InvocationTargetException {
    checkNotNull(event);
    try {
      method.invoke(target, new Object[] { event });
    } catch (IllegalArgumentException e) {
      throw new Error("Method rejected target/argument: " + event, e);
    } catch (IllegalAccessException e) {
      throw new Error("Method became inaccessible: " + event, e);
    } catch (InvocationTargetException e) {
      if (e.getCause() instanceof Error) {
        throw (Error) e.getCause();
      }
      throw e;
    }
  }