Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android平台中,EventBus研究學習

android平台中,EventBus研究學習

編輯:關於Android編程

當一個Android應用功能越來越多的時候,app中各個部分之間通信,往往采用Observer的方式來進行,即注冊----通知----注銷的方式執行 各類控件經常需要根據某個狀態來更新顯示內容。這種場景常見的解決方式就是定義一個接口,需要關注該事件的控件來實現這個接口。 接口類: public interface OnChangedListener { void onDataChanged(); }
被觀察者往往以如下形式實現:
public abstract class AbsHTTPRequest {
    private final WeakHashMap mListeners = new WeakHashMap();
    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 keys = mListeners.keySet();
        if(keys != null) {
            Iterator 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,可以很方便的幫助我們實現觀察者模式,並且讓各個組件之間的耦合性更低。
關於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.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;
... ... ... ... ... ... ... ... ... ... ... ...
}
類EventBus中,有兩個核心的成員
   /*EventType -> List,事件到訂閱對象之間的映射*/
    private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
  /* Subscriber -> List,訂閱對象到它訂閱的的所有事件的映射關系*/
    private final Map>> 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 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
數組對象Method[],調用getMethods()方法, 獲取的是類的所有共有方法,這就包括自身的所有public方法,和從基類繼承的、從接口實現的所有public方法。這也是為啥,我們的onEvent函數,要定義為public方法的原因哦。 在findSubscriberMethods函數中,進行如此頻繁的遍歷,就是為了找到List。 每一個訂閱者,對應一個List,有多少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> findEventTypes(Class eventClass) {
        synchronized (eventTypesCache) {
            List> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList>();
                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的接口方法的多次、頻繁的定義。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved