哎呀呀
最近感覺框架上非常弱雞蝌衔,于是找到了EventBus,想通過解析源碼蝌蹂,學習架構設計最后并手寫實現(xiàn)EventBus框架胚委。
那么,gogogo 先從源碼查看出發(fā)叉信,一步一步實現(xiàn)自己的EventBus吧亩冬;
路漫漫其修遠兮
01. 手寫EventBus框架——源碼分析1
02. 手寫EventBus框架——源碼分析2
03. 手寫EventBus框架——動手_整體架構設計
04. 手寫EventBus框架——動手_終結
1. 訂閱、取消訂閱
EventBus3.0 使用方式如下:
public class SampleComponent extends Fragment
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
EventBus.getDefault().register(this);
}
@Subscribe
public void gogogo(param)
{
}
@Override
public void onDestroy()
{
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
1.1 注冊
1.1.1 注冊源碼分析
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
//獲取該類所有訂閱的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//訂閱方法
subscribe(subscriber, subscriberMethod);
}
}
}
// 緩存訂閱方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod){
//緩存數(shù)據(jù) 至 subscriptionsByEventType硼身;
//緩存數(shù)據(jù) 至 typesBySubscriber硅急;
//緩存數(shù)據(jù) 至 stickyEvents;
}
以上就是 register 所做的事情;
-
subscriberMethodFinder.findSubscriberMethods(subscriberClass)
找到所有 EventBus 匹配的方法佳遂; - 循環(huán)逐個調用緩存訂閱方法
subscribe
营袜,最終緩存進入subscriptionsByEventType
和typesBySubscriber
;
看一下如何找到匹配方法列表的丑罪;
*** SubscriberMethodFinder.class ***
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//使用反射查找荚板。
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 使用Info取出方法 默認該方法
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
以上可以看出 本質都是調用 findUsingReflection
*** SubscriberMethodFinder.class ***
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
//這里的 clazz == subscriberClass;
while (findState.clazz != null) {
//找到只有一個參數(shù)的 方法集合;
findUsingReflectionInSingleClass(findState);
//轉移到 父 Clazz
findState.moveToSuperclass();
}
//這里 就是返回 findState.subscriberMethods;
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 找到所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// 找到 public方法,包含繼承和接口的方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
//判斷修飾符, Public 不包含 static, abstaact
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//判斷方法數(shù)為 1
if (parameterTypes.length == 1) {
//獲取注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
//拋異常
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
//拋異常
}
}
}
這一段可以看出它的實現(xiàn)機制:核心原理是反射吩屹。
亮點:其中判斷標識符的方式 與Android源碼非常類似跪另;
int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
//判斷修飾符, Public 不包含 static, abstaact
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0)
{
//...
}
1.1.2 小結——注冊事件分析
注冊的源碼已經分析過了煤搜,來個小小的總結
流程:
- 先找到所有 方法數(shù)量為1個且?guī)в?code>@Subscribe注解的方法
- 將方法寄存進我們的緩存當中(
subscriptionsByEventType
和typesBySubscriber
和stickyEvents
)
其它收獲
-
CopyOnWriteArrayList
線程讀寫安全的列表 -
ConcurrentHashMap
支持檢索的完全并發(fā)性的哈希表 - 存儲的一個設計免绿,非常巧妙。
1.2 取消注冊
比較簡單擦盾。緩存清除
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
// 移除
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
2. 發(fā)布
我們平常調用時這樣的
EventBus.getDefault().post(param);
//或者
EventBus.getDefault().postSticky(param);
o.O
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
public void post(Object event) {
//...
}
本質都是調用 post 方法;
2.2 post (Object event)
讓我們來瞧瞧 它是什么鬼
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
public void post(Object event) {
//獲取當前線程 的 PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
//添加到消息列表
eventQueue.add(event);
if (!postingState.isPosting) {
//判斷是否是主線程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
//狀態(tài)改為true
postingState.isPosting = true;
//...
try {
while (!eventQueue.isEmpty()) {
//發(fā)送
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//... 還原狀態(tài)
}
}
}
這邊可以看到 先會從 currentPostingThreadState 取出狀態(tài)嘲驾,各種判斷 然后調用postSingleEvent
淌哟。
postSingleEvent
這可是塊硬骨頭;
再難也要啃下它辽故,哼哼...
2.3 postSingleEvent()
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//
//...
// 進入
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
//...
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
//...
//如果沒有執(zhí)行徒仓,第一次會進入以下方法
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
// 包裝成 NoSubscriberEvent 方法
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//獲取 subscriptions
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//...
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
//...
}
}
return true;
}
return false;
}
最后調用方法 在不同的線程內。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
2.3.1 小結——Post事件分析
** 流程**
- 根據(jù)EventType 得到subscriptions = subscriptionsByEventType 中的CopyOnWriteArrayList<Subscription>;
- 循環(huán) subscriptions誊垢,并調用
postToSubscription
發(fā)送 ; -
postToSubscription
內根據(jù)線程類型來執(zhí)行方法掉弛; - 發(fā)布了以后 緩存方法直接執(zhí)行。
使用注意點:
從這邊的分析可以看出來彤枢,post調用以后,會直接執(zhí)行訂閱方法筒饰,那么訂閱方(Activity)不在棧頂?shù)臅r候缴啡,如果做些動畫展示,那是很耗性能的瓷们,那就尷尬了业栅。。
這邊梳理了整個事件的流程與原理谬晕,順帶也收獲到了一些干貨
細節(jié)方面沒有那么深入碘裕。
希望我的文章不會誤導在觀看的你,如果有異議的地方歡迎討論和指正攒钳。
如果能給觀看的你帶來收獲帮孔,那就是最好不過了。