開篇廢話
近期利用業(yè)余時(shí)間后添,跟著大神把Eventbus的框架學(xué)習(xí)了一下愤钾,在這里触创,記錄一下這次學(xué)習(xí)的心得坎藐。
EventBus是針一款對(duì)Android的發(fā)布/訂閱事件總線。它可以讓我們很輕松的實(shí)現(xiàn)在Android各個(gè)組件之間傳遞消息哼绑,并且代碼的可讀性更好岩馍,耦合度更低。
這次學(xué)習(xí) 抖韩,大概有以下這些知識(shí)點(diǎn):
1.注解和反射的使用
2.學(xué)習(xí)Eventbus的實(shí)現(xiàn)原理
需要注意的是蛀恩,本次記錄是從實(shí)現(xiàn)的角度來進(jìn)行記錄的,可能跟我們調(diào)用的邏輯順序不一樣茂浮。
技術(shù)詳情
1. 事件接收者訂閱想要的事件
這一步實(shí)現(xiàn)的是双谆,告訴事件生產(chǎn)者,我有這些事件需要處理席揽,通過注解進(jìn)行標(biāo)記顽馋,方便我們的框架進(jìn)行收集此類需要處理的事件,例如以下這些操作:
@Subscribe(threadMode = ThreadMode.MainThread)
public void showTextView(SenduoEvent senduoEvent){
tvSenduobusInfo.setText(senduoEvent.toString());
}
@Subscribe(threadMode = ThreadMode.Async)
public void showLog(SenduoEvent senduoEvent){
Log.e(TAG,senduoEvent.toString());
}
通過以上步驟幌羞,就相當(dāng)于告訴我們的框架寸谜,這里需要處理這兩個(gè)事件
2. 往事件生產(chǎn)者注冊(cè) 和 反注冊(cè)想要訂閱的事件
通過第一步,事件接收者已經(jīng)把想要接收的事件告知了我們這個(gè)框架新翎,我們這個(gè)框架程帕,就需要通過不同的類來收集這些事件,調(diào)用者地啰,通過調(diào)用以下這行代碼愁拭,框架就會(huì)進(jìn)行收集記錄各自訂閱的事件:
Senduobus.getDefault().register(this);
這一步,框架其實(shí)做了蠻多工作的亏吝。
首先岭埠,通過方法的注解,記錄當(dāng)前類訂閱的所有事件
public void register(Object activity){
List<SubscribleMethod> list = cacheMap.get(activity);
if(list == null){
list = getSubscribleMethods(activity);
cacheMap.put(activity,list);
}
}
這里的getSubscribleMethods(Object)方法就是通過類的注解,來獲取處理事件的方法:
private List<SubscribleMethod> getSubscribleMethods(Object activity) {
List<SubscribleMethod> list = new ArrayList<>();
Class clazz = activity.getClass();
while(clazz != null){
String name = clazz.getName();
if(name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("android.")){//如果類全名以這些字符開頭惜论,則認(rèn)為是jdk的许赃,不是我們自定義的,自然沒必要去拿注解
break;
}
Method[] methods = clazz.getDeclaredMethods();//獲得當(dāng)前class所有生命的public方法
for(Method method : methods){
Subscribe subscribe = method.getAnnotation(Subscribe.class);
if(subscribe == null){
continue;
}
Class[] paratems = method.getParameterTypes();
if(paratems.length != 1){
throw new RuntimeException("senduobus 只能接收到一個(gè)參數(shù)");
}
ThreadMode threadMode = subscribe.threadMode();
SubscribleMethod subscribleMethod = new SubscribleMethod(method,threadMode,paratems[0]);
list.add(subscribleMethod);
}
clazz = clazz.getSuperclass();
}
return list;
}
然后馆类,通過一個(gè)內(nèi)存緩存Map記錄類與對(duì)應(yīng)類的訂閱事件混聊,減少框架反射的次數(shù)
3. 事件生產(chǎn)者分發(fā)事件
通過以上兩步,事件接收者乾巧,以及其訂閱的事件都已經(jīng)收集并且綁定好了句喜,就差事件生產(chǎn)者進(jìn)行分發(fā)消息了。
這里需要注意的是沟于,如何確認(rèn)當(dāng)前這個(gè)事件需要由哪個(gè)接收者來處理咳胃,框架中,是通過方法的參數(shù)類型進(jìn)行分發(fā)確認(rèn)的旷太,以下這種形式:
Senduobus.getDefault().post(new SenduoEvent("1","測(cè)試發(fā)送消息"));
其中SenduoEvent類展懈,通過這個(gè)類來確認(rèn)該由哪些事件接收者來處理事件:
public void post(final Object senduoEvent){
Set<Object> set = cacheMap.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
final Object activity = iterator.next();
List<SubscribleMethod> list = cacheMap.get(activity);
for(final SubscribleMethod subscribleMethod : list){
if(subscribleMethod.getEventType().isAssignableFrom(senduoEvent.getClass())){
switch(subscribleMethod.getThreadMode()){
case Async:
if(Looper.myLooper() == Looper.getMainLooper()){
executorService.execute(new Runnable() {
@Override
public void run() {
invoke(subscribleMethod,activity,senduoEvent);
}
});
}else{
invoke(subscribleMethod,activity,senduoEvent);
}
break;
case PostThread:
break;
case MainThread:
if(Looper.myLooper() == Looper.getMainLooper()){
invoke(subscribleMethod,activity,senduoEvent);
}else{
handler.post(new Runnable() {
@Override
public void run() {
invoke(subscribleMethod,activity,senduoEvent);
}
});
}
break;
case BackgroundThread:
break;
default:
break;
}
}
}
}
}
里面有一些線程切換的邏輯,具體可查看ThreadMode中的注釋供璧,方便理解存崖。
以下是此項(xiàng)目的源碼: