一、前言
最近研究了一下項目上用的一個類EventBus框架,由於EventBus都在對象初始化的時候註冊,導致啓動非常耗時(註冊是要遍歷所有方法的),另外發現比較多消息處理的方法耗時非常長,導致後面的方法等待時間很長,而因爲同一個業務包含了很多個模塊,分屬不同的部門負責,而這些模塊共用一個EventBus,導致維護相當困難,所以花了幾個小時,參考了相關框架,做了一個輕量級的EventBus框架,即LightEventBus,採用的懶遍歷方式,即不在註冊的時候遍歷方法,同時引入分組的概念,可以按照業務分組或者組件分組,事件分發相互隔離,並且增加了請求-響應模型,當想要什麼數據的時候,可以發送事件去請求數據,增加鉤子,管理生命週期,即使不註銷也不會出現內存泄露。因爲考慮到異步會讓框架比較大,做不到輕量,故暫不支持異步。
二、LightEventBus介紹
github地址:https://github.com/newhope1106/lighteventbus
下面引用github上的介紹
輕量級EventBus是什麼
輕量級EventBus,即LightEventBus,主要面向業務單元或組件級別的通信框架,提出了分組的概念,具有以下特性:
1.特意設計成不支持異步,以業務單元劃分或組件單元劃分的常見通信,異步使用極少,而且異步會導致框架變得臃腫,這也就是輕量級的含義
2.支持組件級別的生命週期,也就是不需要在代碼中手動註銷,只需要通過鉤子勾到組件裏面,就可以和該組件生命週期一致
3.輕量級EventBus支持兩種模式,發佈-訂閱模式,以及請求-響應模式,其中第二種是EventBus所沒有的,另外發布-訂閱模式的實現方式也和EventBus不太一樣,效率更高
爲什麼要用輕量級EventBus
- EventBus面向的是大型業務級別場景,根據業務可以包含多個業務模塊,如果多個業務模塊接入的消息過多,會導致消息堵塞,舉個例子,如果有1000個方法註冊了同一個消息,處於同一個隊列的情況,需要等前面的方法執行完成才能執行到自己,而方法本身是不知道要等這麼長的,跨模塊的方式也更會導致管理上的困難。LightEventBus則適合在業務單元或組件內使用,所見即所得,由業務單元或組件內來管理。(EvenBus雖然也支持單獨實例化,但如果一個組件生成一個EventBus實例,豈不臃腫)
- EventBus的註冊和註銷是配套使用的,並且在註冊時,就會遍歷對象的所有方法,如果一啓動就有非常多的對象需要監聽,會嚴重影響性能,此外不註銷會導致內存泄露,但有時註銷不是那麼方便的。LightEventBus雖然也需要調用註冊接口,但真正的方法查找,只有等真正發送消息時纔會去遍歷,採用的是懶漢方式。另外可以不用調用註銷方法,因爲本身是和組件同生命週期的
- EventBus只支持發佈-訂閱模式,而且一個方法對應一個消息,但是LightEventBus則從另外一種角度來詮釋,可以解決方法數限制的問題(方法個數不能超過65535),且方法調用效率更高(把消息作爲Key值,而不是遍歷所有方法),EventBus採用的是遍歷方式查找方法,此外LightEventBus還支持請求-響應模式。
添加LightEventBus
gradle依賴
compile 'com.appleye.eventbus:LightEventBus:1.0.0'
或者
implementation 'com.appleye.eventbus:LightEventBus:1.0.0'
maven依賴
<dependency>
<groupId>com.appleye.eventbus</groupId>
<artifactId>LightEventBus</artifactId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
LightEventBus架構簡單示意圖
三、LightEventBus使用
github源碼裏面有幾種情況的例子,可以參考源碼,下面簡單介紹貼一下代碼介紹如何使用
1.在build.gradle中增加依賴
implementation 'com.appleye.eventbus:LightEventBus:1.0.0'
2.定義分組
public class Constants {
public static final String GROUP_MAIN = "demo";
}
3.定義事件
public class EventApi {
//分發數據事件
public static final String EVENT_SAY_HELLO = "lightbus://say/hello";
//請求數據事件
public static final String EVENT_REQUEST_MSG = "lightbus/request/message";
}
4.註冊訂閱者、增加鉤子、分發數據和請求數據、處理多事件、處理單事件
public class MainActivity extends AppCompatActivity {
@Hook
private IEventBus mEventBus;//鉤子
//計數
private AtomicInteger mCounter = new AtomicInteger(0);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//註冊訂閱者,增加鉤子
EventBusFac.getInstance(Constants.GROUP_MAIN).register(this).hook(this);
findViewById(R.id.hello_world_tv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mEventBus != null) {
//請求數據(請求-響應模型)
Event requestEvent = new Event(EventApi.EVENT_REQUEST_MSG);
Response response = mEventBus.request(requestEvent);
if(response != null && Response.OK == response.resultCode) {
//分發數據(訂閱發佈模型)
Event event = new Event(EventApi.EVENT_SAY_HELLO);
event.data = response.body;
mEventBus.postEvent(event);
}
}
}
});
}
//處理多個事件
@Subscriber(eventType = {EventApi.EVENT_SAY_HELLO, EventApi.EVENT_REQUEST_MSG})
public void handleEvent(Event event) {
switch (event.type){
case EventApi.EVENT_SAY_HELLO:{
//處理分發數據事件
Toast.makeText(this, (String)event.data, Toast.LENGTH_SHORT).show();
break;
}
case EventApi.EVENT_REQUEST_MSG:{
//處理請求數據事件
if(mEventBus != null) {
mEventBus.response(event, "Hello World!!!");
}
break;
}
}
}
//處理單個事件
@Subscriber(eventType = {EventApi.EVENT_SAY_HELLO})
public void handleSayHelloEvent(Event event) {
if(EventApi.EVENT_SAY_HELLO.equals(event.type)){
((TextView)findViewById(R.id.count_tv)).setText(String.valueOf(mCounter.incrementAndGet()));
}
}
}
四、後續計劃
後續會考慮看是否有簡單的方式增加異步,並且還會增加性能埋點接口,歡迎所有人star、fork源碼以及提交issue,謝謝百忙之中抽空閱讀本篇博客!