1.概述
看過(guò)我之前關(guān)于EventBus 講解的文章《EventBus原理與源碼解析》,可以了解到EventBus是針對(duì)Android優(yōu)化的發(fā)布-訂閱事件總線,簡(jiǎn)化了Android組件間的通信。有了EventBus已經(jīng)很方便我們平時(shí)日常開(kāi)發(fā)中的組件通信了,但在仔細(xì)研讀其源碼之后,我也在之前的文章中提到了兩個(gè)疑問(wèn):
- 其消息給人感覺(jué)是一種亂跳的感覺(jué),因?yàn)槠洳捎米⒔獾姆绞?,這點(diǎn)感覺(jué)對(duì)業(yè)務(wù)邏輯梳理并不一定占有優(yōu)勢(shì),就拿Android Studio來(lái)說(shuō),居然會(huì)提示該方法無(wú)處使用。
- 采用反射方法invokeSubscriber來(lái)消費(fèi)事件,效率如何。
基于以上的兩個(gè)疑問(wèn),結(jié)合我目前做的項(xiàng)目,大概簡(jiǎn)單寫(xiě)了個(gè)同EventBus 具備相同功能框架 NotificationCenter。以下是關(guān)于NotificationBus的一些基本講解。
2.基本使用
NotificationBus的基本使用和EventBus使用相差無(wú)幾,均需要注冊(cè),發(fā)布,反注冊(cè)這幾個(gè)步驟。其基本流程圖如下:

2.1基本結(jié)構(gòu)
從下圖我們可以看出整個(gè)框架代碼結(jié)構(gòu)非常精簡(jiǎn),同EventBus一樣也是基于觀察者模式來(lái)設(shè)計(jì)的。

2.2 使用方法
- 項(xiàng)目引用NotificationBus,在項(xiàng)目的build文件中添加
compile project(path: ':notificatonlibrary') - 注冊(cè):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NotificationCenter.defaultCenter().subscriber(TOP_KEY,subscriber);
NotificationCenter.defaultCenter().subscriber(EventSubscriber.class,eventSubscriber);
initView();
}
- 反注冊(cè):
@Override
protected void onDestroy() {
super.onDestroy();
NotificationCenter.defaultCenter().unsubscribe(TOP_KEY,subscriber);
NotificationCenter.defaultCenter().unsubscribe(EventSubscriber.class,eventSubscriber);
}
- 發(fā)布消息
public void onClick(View v) {
int viewId = v.getId();
if (viewId==R.id.bt_send){
NotificationCenter.defaultCenter().publish("top_key",null);
EventSubscriber eventSubscriber = new EventSubscriber();
NotificationCenter.defaultCenter().publish(eventSubscriber);
}
}
可以看到我們輸出的log如下

基本使用就是這么簡(jiǎn)單,具體可以參照Demo。
3. 源碼解讀
3.1注冊(cè),從上述使用的過(guò)程我們可以看到,存在兩種注冊(cè)方式
NotificationCenter.defaultCenter().subscriber(TOP_KEY,subscriber);和NotificationCenter.defaultCenter().subscriber(EventSubscriber.class,eventSubscriber);兩種方式。首先先看defaultCenter 這個(gè)方法
public static NotificationCenter defaultCenter() {
if (_instanceCenter == null) {
_instanceCenter = new NotificationCenter();
}
return _instanceCenter ;
}
也是一個(gè)單例模式,我們來(lái)看看構(gòu)造方法NotificationCenter
private NotificationCenter() {
Looper looper = Looper.getMainLooper();
mHandler = new Handler(looper);
}
會(huì)創(chuàng)建一個(gè)mHandler對(duì)象,這個(gè)是消息發(fā)送的根本。
從其中調(diào)用可以看,采用了對(duì)象作為第二個(gè)參數(shù),消息傳遞過(guò)來(lái),當(dāng)然是在subscriber對(duì)象中去處理業(yè)務(wù)邏輯。這就解決了個(gè)人對(duì)EventBus的注解疑惑,畢竟這樣做至少?gòu)拇a層面可以看出無(wú)未被使用的代碼,而注解的話unused方法Android Studio一直提示,強(qiáng)迫癥不喜歡,哈哈哈。下面以此看兩種注冊(cè)方式
/**
* 訂閱消息
*
* @param topic 主題key
* @param subscriber 回調(diào)接口
* @return
*/
public boolean subscriber(String topic, TopicSubscriber subscriber) {
if (TextUtils.isEmpty(topic)) {
throw new IllegalArgumentException(
"Topic must not be null or empty");
}
if (subscriber == null) {
throw new IllegalArgumentException(
"Event subscriber must not be null");
}
return subscribe(topic, subscribersByTopic,
new WeakReference<TopicSubscriber>(subscriber));
}
public boolean subscriber(Class eventClass, Subscriber subscriber) {
if (eventClass == null) {
throw new IllegalArgumentException("Event class must not be null");
}
if (subscriber == null) {
throw new IllegalArgumentException(
"Event subscriber must not be null");
}
return subscribe(eventClass, subscribersByClass,
new WeakReference<Subscriber>(subscriber));
}
可以看到兩個(gè)傳入?yún)?shù)基本無(wú)差別,topic類型的忽略。以class傳入?yún)?shù)的方法我們通過(guò)上文可以看到是NotificationCenter.defaultCenter().subscriber(EventSubscriber.class,eventSubscriber);再看EventSubscriber類
/**
* FileName: EventSubscriber
* Author: owen.zhan
* Date: 2018/10/26 16:52
*/
public class EventSubscriber {
}
其實(shí)其根本沒(méi)做任何特殊處理,就是一個(gè)簡(jiǎn)單的java 類。而eventSubscriber對(duì)象則是
Subscriber<EventSubscriber> eventSubscriber = new Subscriber<EventSubscriber>() {
@Override
public void onEvent(EventSubscriber event) {
NLog.d(NotificationCenter.TAG,"onEvent====");
}
};
由此可見(jiàn)消息返回后均在onEvent方法中去處理業(yè)務(wù)邏輯。
下面繼續(xù)回過(guò)頭來(lái)看注冊(cè),從上面注冊(cè)的代碼我們可知,最終均是采用方法subscribe ,只是會(huì)區(qū)分topic還是class類型去注冊(cè):
采用Topic來(lái)注冊(cè)
protected boolean subscribe(final Object classTopicOrPatternWrapper,
final Map<Object, Object> subscriberMap, final Object subscriber) {
if (classTopicOrPatternWrapper == null) {
throw new IllegalArgumentException("Can't subscribe to null.");
}
if (subscriber == null) {
throw new IllegalArgumentException(
"Can't subscribe null subscriber to "
+ classTopicOrPatternWrapper);
}
boolean alreadyExists = false;
Object realSubscriber = subscriber;
boolean isWeakRef = subscriber instanceof WeakReference;
if (isWeakRef) {
realSubscriber = ((WeakReference) subscriber).get();
}
boolean isWeakProxySubscriber = false;
//1
if (subscriber instanceof ProxySubscriber) {
ProxySubscriber proxySubscriber = (ProxySubscriber) subscriber;
isWeakProxySubscriber = proxySubscriber.getReferenceStrength() == ReferenceStrength.WEAK;
if (isWeakProxySubscriber) {
realSubscriber = ((ProxySubscriber) subscriber)
.getProxiedSubscriber();
}
}
if (isWeakRef && isWeakProxySubscriber) {
throw new IllegalArgumentException(
"ProxySubscribers should always be subscribed strongly.");
}
if (realSubscriber == null) {
return false;
}
synchronized (listenerLock) {//2
//判斷該top是否已經(jīng)被注冊(cè)
List currentSubscribers = (List) subscriberMap
.get(classTopicOrPatternWrapper);
if (currentSubscribers == null) {//3
currentSubscribers = new ArrayList();
subscriberMap.put(classTopicOrPatternWrapper,
currentSubscribers);
} else {
for (Iterator iterator = currentSubscribers.iterator(); iterator
.hasNext(); ) {
Object currentSubscriber = iterator.next();
Object realCurrentSubscriber = getRealSubscriberAndCleanStaleSubscriberIfNecessary(
iterator, currentSubscriber);
if (realSubscriber.equals(realCurrentSubscriber)) {
iterator.remove();
alreadyExists = true;
}
}
}
currentSubscribers.add(subscriber);
return !alreadyExists;
}
}
- 判斷是topic注冊(cè)還是其他類型注冊(cè)。
- 判斷該對(duì)象是否已經(jīng)被注冊(cè),前面部分代碼作出基本判斷。
private Map subscribersByTopic = new HashMap();//根據(jù)topic 來(lái)注冊(cè)的消息
private Map subscribersByClass = new HashMap();//根據(jù)對(duì)象來(lái)注冊(cè)的消息
3.2 發(fā)送消息
從上文我們可知消息最終是采用publish方法發(fā)出去。
/**
* 發(fā)送消息
*
* @param topicName
* @param eventObj
*/
public void publish(String topicName, Object eventObj) {
mHandler.post(new PublishRunnable(null, topicName, eventObj, getSubscribersToTopic(topicName)));
}
/**
* topic 為class
* @param event
*/
public void publish(Object event) {
if (event == null) {
throw new IllegalArgumentException("Cannot publish null event.");
}
mHandler.post(new PublishRunnable(event, null, null, getSubscribers(event.getClass())));
}
可以看出最終均是通過(guò)handler來(lái)處理一個(gè)PublishRunnable,我們下面來(lái)看看該類:
class PublishRunnable implements Runnable {
Object theEvent;
String theTopic;
Object theEventObject;
List theSubscribers;
public PublishRunnable(final Object event, final String topic,
final Object eventObj, final List subscribers) {
this.theEvent = event;
this.theTopic = topic;
this.theEventObject = eventObj;
this.theSubscribers = subscribers;
}
@Override
public void run() {
publish(theEvent, theTopic, theEventObject, theSubscribers);
}
}
繼續(xù)往下查看:publish方法:
protected void publish(final Object event, final String topic,
final Object eventObj, final List subscribers) {
if (event == null && topic == null) {
throw new IllegalArgumentException(
"Can't publish to null topic/event.");
}
if (subscribers == null || subscribers.isEmpty()) {
return;
}
for (int i = 0; i < subscribers.size(); i++) {
Object eh = subscribers.get(i);
//區(qū)分是主題類型還是對(duì)象類型
if (event != null) {
Subscriber eventSubscriber = (Subscriber) eh;
try {
//1
eventSubscriber.onEvent(event);
} catch (Throwable e) {
}
} else {
//2
TopicSubscriber eventTopicSubscriber = (TopicSubscriber) eh;
try {
eventTopicSubscriber.onEvent(topic, eventObj);
} catch (Throwable e) {
}
}
}
}
可以看到該方法是用來(lái)遍歷前面提到的集合,然后再判斷注冊(cè)的類型,最終到達(dá)消息傳遞的功能。
- class 注冊(cè)方式來(lái)處理。
- topic 注冊(cè)方式來(lái)處理。
3.3 反注冊(cè)
/**
*
* @param cl
* @param subscriber
* @return
*/
public boolean unsubscribe(Class cl, Subscriber subscriber) {
return unsubscribe(cl, subscribersByClass, subscriber);
}
/**
* 反向注冊(cè)
*
* @param topic
* @param subscriber
* @return
*/
public boolean unsubscribe(String topic, TopicSubscriber subscriber) {
return unsubscribe(topic, subscribersByTopic, subscriber);
}
可以看到最終均是走向unubscribe方法,那么我們來(lái)看看這個(gè)方法
protected boolean unsubscribe(Object o, Map subscriberMap, Object subscriber) {
if (o == null) {
throw new IllegalArgumentException("Can't unsubscribe to null.");
}
if (subscriber == null) {
throw new IllegalArgumentException(
"Can't unsubscribe null subscriber to " + o);
}
synchronized (listenerLock) {
return removeFromSetResolveWeakReferences(subscriberMap, o,
subscriber);
}
}
可以發(fā)現(xiàn)是走向了removeFromSetResolveWeakReferences 方法,繼續(xù)往下查看
private boolean removeFromSetResolveWeakReferences(Map map, Object key,
Object toRemove) {
List subscribers = (List) map.get(key);
if (subscribers == null) {
return false;
}
if (subscribers.remove(toRemove)) {
if (toRemove instanceof WeakReference) {
// decWeakRefPlusProxySubscriberCount();
}
if (toRemove instanceof ProxySubscriber) {
((ProxySubscriber) toRemove).proxyUnsubscribed();
// decWeakRefPlusProxySubscriberCount();
}
return true;
}
// search for WeakReferences and ProxySubscribers
for (Iterator iter = subscribers.iterator(); iter.hasNext(); ) {
Object existingSubscriber = iter.next();
if (existingSubscriber instanceof ProxySubscriber) {
ProxySubscriber proxy = (ProxySubscriber) existingSubscriber;
existingSubscriber = proxy.getProxiedSubscriber();
if (existingSubscriber == toRemove) {
removeProxySubscriber(proxy, iter);
return true;
}
}
if (existingSubscriber instanceof WeakReference) {
WeakReference wr = (WeakReference) existingSubscriber;
Object realRef = wr.get();
if (realRef == null) {
// clean up a garbage collected reference
iter.remove();
// decWeakRefPlusProxySubscriberCount();
return true;
} else if (realRef == toRemove) {
iter.remove();
// decWeakRefPlusProxySubscriberCount();
return true;
} else if (realRef instanceof ProxySubscriber) {
ProxySubscriber proxy = (ProxySubscriber) realRef;
existingSubscriber = proxy.getProxiedSubscriber();
if (existingSubscriber == toRemove) {
removeProxySubscriber(proxy, iter);
return true;
}
}
}
}
return false;
}
整體功能就是判斷類型,依次清理上述說(shuō)的兩個(gè)集合subscribersByTopic和subscribersByClass。
整NotificationCenter 基本使用和邏輯結(jié)構(gòu)基本如此,詳細(xì)的可以參照Demo去研究和拓展。
4 . 總結(jié)
NotificationBus 是根據(jù)項(xiàng)目需求,結(jié)合EventBus來(lái)寫(xiě)的一個(gè)消息訂閱框架,歡迎各位大神來(lái)多多補(bǔ)充和交流。關(guān)于其中個(gè)人覺(jué)得的優(yōu)缺點(diǎn)作出以下幾點(diǎn)簡(jiǎn)單說(shuō)明,歡迎拍磚。
優(yōu)點(diǎn):
- 整體采用map來(lái)管理,最終是遍歷集合查找,相對(duì)EventBus采用對(duì)象綁定,然后最終采用反射來(lái)調(diào)用,性能方面會(huì)更好一點(diǎn)。
- 沒(méi)有用注解,個(gè)人覺(jué)得使用起來(lái)業(yè)務(wù)邏輯清晰。
- 比EventBus更輕量化。
缺點(diǎn):
1 . 沒(méi)有EventBus會(huì)區(qū)分線程來(lái)注冊(cè)和發(fā)布消息,這點(diǎn)不夠全面。
以上是根據(jù)EventBus 的源碼研究和結(jié)合項(xiàng)目需求來(lái)寫(xiě)的,中間會(huì)存在很多問(wèn)題,希望各位大神多多指教。