Android開(kāi)源項(xiàng)目原理系列
[搞定開(kāi)源01] okhttp 3.10原理
[搞定開(kāi)源02] okio 1.14原理
[搞定開(kāi)源03] retrofit 2.4.0與設(shè)計(jì)模式
[搞定開(kāi)源04] 手動(dòng)實(shí)現(xiàn)RxJava2線程切換
EventBus是Android的發(fā)布訂閱開(kāi)源庫(kù)齿风,優(yōu)勢(shì)和使用方法不用說(shuō)了药薯,簡(jiǎn)單過(guò)一下源碼,了解核心原理救斑。
當(dāng)前EventBus最新版本是3.1.1童本,和前代相比,方法名可以自定義脸候,新增注解支持穷娱。
EventBus構(gòu)造函數(shù)
優(yōu)秀開(kāi)源庫(kù)的基本特征是,常用功能用一個(gè)入口類就可以玩轉(zhuǎn)运沦,EventBus也是泵额。
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
獲取EventBus對(duì)象常規(guī)使用getDefault,典型的Double Check獲取單例携添。如果有特別需求嫁盲,可以通過(guò)EventBusBuilder,典型的建造者模式薪寓。
EventBus構(gòu)造函數(shù)創(chuàng)建了十多個(gè)對(duì)象亡资,關(guān)注其中的:
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
//...
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
//...
}
Log
EventBus的日志打印使用Logger接口澜共,已經(jīng)實(shí)現(xiàn)了:
- AndroidLogger
- JavaLogger
- SystemOutLogger
static final boolean ANDROID_LOG_AVAILABLE;
static {
boolean android = false;
try {
android = Class.forName("android.util.Log") != null;
} catch (ClassNotFoundException e) {
// OK
}
ANDROID_LOG_AVAILABLE = android;
}
public static boolean isAndroidLogAvailable() {
return ANDROID_LOG_AVAILABLE;
}
對(duì)于Android,直接嘗試獲取Log類锥腻,同時(shí)用來(lái)判斷當(dāng)前是否Android嗦董。
獲取Android的UI線程
EventBus如何讓事件執(zhí)行在Android的UI線程呢?
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
Object getAndroidMainLooperOrNull() {
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
這里用到了上面判斷Android的方法瘦黑,如果是京革,創(chuàng)建AndroidHandlerMainThreadSupport,保存了Looper.getMainLooper()幸斥。很熟悉吧匹摇,這就是Android的UI線程Looper。
Poster
EventBus的event可以指定運(yùn)行在UI線程或者后臺(tái)線程甲葬,靠的就是Poster廊勃,下文會(huì)說(shuō)到,透露一丟丟:
- UI線程:MainLooper
- 后臺(tái)線程:線程池
注冊(cè)/取消注冊(cè)
想要接收EventBus發(fā)送的事件经窖,對(duì)象必須先注冊(cè)坡垫,停止接收時(shí)取消注冊(cè)。注冊(cè)過(guò)程画侣,本質(zhì)是通知EventBus查找對(duì)象中的訂閱方法冰悠。
Subscribe注解
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent4Main(MsgEvent event) {}
EventBus3之后,訂閱方法名改為自定義配乱,通過(guò)注解描述溉卓。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
boolean sticky() default false;
int priority() default 0;
}
除了基礎(chǔ)的ThreadMode線程模型,還可以定義粘性事件和優(yōu)先級(jí)搬泥。
注解信息桑寨,在注冊(cè)過(guò)程最后由SubscriberMethod類描述。
注冊(cè)過(guò)程
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
注冊(cè)時(shí)傳入訂閱對(duì)象佑钾,兩部操作:
- 分析訂閱對(duì)象的類西疤,SubscriberMethodFinder從中查找訂閱方法,包裝為SubscriberMethod休溶。
- 調(diào)用subscribe代赁,數(shù)據(jù)轉(zhuǎn)化為EventBus內(nèi)部的兩個(gè)Map。
List<SubscriberMethod>
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//1
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//2
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//3
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
- 查找目標(biāo)類的訂閱方法前兽掰,先查找緩存METHOD_CACHE芭碍,用的是ConcurrentHashMap,因?yàn)橐幚矶嗑€程孽尽。
Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>()
- 默認(rèn)創(chuàng)建的EventBus對(duì)象ignoreGeneratedIndex=false窖壕,先看findUsingInfo
- 獲取List成功后,保存在緩存METHOD_CACHE
SubscriberMethodFinder.FindState
上面第二步重點(diǎn)是使用SubscriberMethodFinder的內(nèi)部類FindState執(zhí)行查找過(guò)程:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//1
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
//2
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 {
//3
findUsingReflectionInSingleClass(findState);
}
//4
findState.moveToSuperclass();
}
//5
return getMethodsAndRelease(findState);
}
第一步是調(diào)用prepareFindState獲取FindState:
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
FindState的創(chuàng)建不是直接new,而是嘗試從FIND_STATE_POOL中獲取(最多保存4個(gè))瞻讽,目測(cè)是享元模式鸳吸,沒(méi)有才new對(duì)象。
第二步進(jìn)入循環(huán)速勇,從當(dāng)前類開(kāi)始晌砾,遍歷父類查找訂閱方法。
這里涉及EventBus3新特性烦磁,運(yùn)行時(shí)反射查找方法當(dāng)然會(huì)慢點(diǎn)养匈,可以使用Subscriber Index在編譯期操作加速,具體不展開(kāi)都伪,直接看else部分呕乎。
第三步的findUsingReflectionInSingleClass,使用反射查找陨晶,細(xì)節(jié)不用展開(kāi)猬仁。
第四步將當(dāng)前查找目標(biāo)切換到父類,繼續(xù)循環(huán)查找珍逸。
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
第五步清理FindState逐虚,放回FIND_STATE_POOL,下次繼續(xù)利用谆膳。
subscribe
register函數(shù)對(duì)每個(gè)SubscriberMethod執(zhí)行subscribe,注意這里synchronized當(dāng)前EventBus對(duì)象撮躁。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//... 粘性事件略
}
subscribe不外乎是對(duì)數(shù)據(jù)的挪騰漱病,目的是構(gòu)建subscriptionsByEventType和typesBySubscriber兩個(gè)Map:
subscriptionsByEventType
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
Subscription包裝了訂閱對(duì)象和訂閱方法,因此Map的key/value對(duì)應(yīng)如下:
event類型 -> List<訂閱對(duì)象,訂閱方法>
表示了event由哪些對(duì)象的哪個(gè)方法訂閱了把曼。
typesBySubscriber
private final Map<Object, List<Class<?>>> typesBySubscriber;
typesBySubscriber簡(jiǎn)單些杨帽,表示訂閱對(duì)象訂閱了哪些event類型:
訂閱對(duì)象 -> List<event類型>
取消注冊(cè)
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 {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
取消注冊(cè)的邏輯很簡(jiǎn)單,將當(dāng)前訂閱者的信息從subscriptionsByEventType和typesBySubscriber中移除嗤军。
發(fā)送
PostingThreadState(每個(gè)線程一份)
EventBus發(fā)送event調(diào)用post方法注盈,首先來(lái)認(rèn)識(shí)EventBus核心的內(nèi)部類PostingThreadState。
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}
PostingThreadState包含eventQueue和一些標(biāo)志變量叙赚,通過(guò)ThreadLocal在每個(gè)線程中維護(hù)一個(gè)對(duì)象(ThreadLocal的initialValue方法初始創(chuàng)建PostingThreadState對(duì)象)老客。
沒(méi)有深?yuàn)W的玄妙,看數(shù)據(jù)結(jié)構(gòu)大概可以知道震叮,EventBus發(fā)送原理是將event入隊(duì)在線程上的PostingThreadState胧砰,再查找訂閱者發(fā)送。
event進(jìn)出隊(duì)
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
發(fā)送event的邏輯很明確苇瓣,取出當(dāng)前線程的PostingThreadState尉间,將event入隊(duì)。當(dāng)不在發(fā)送狀態(tài)時(shí),循環(huán)調(diào)用postSingleEvent發(fā)送所有event哲嘲。
發(fā)送event
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//1
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//2
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
第一部分先收集event的類型贪薪,eventInheritance在EventBus默認(rèn)構(gòu)造函數(shù)里為true,表示會(huì)向上遍歷event的父類眠副。然后調(diào)用postSingleEventForEventType執(zhí)行發(fā)送過(guò)程画切,得到發(fā)送結(jié)果subscriptionFound。
第二部分侦啸,如果找不到訂閱者槽唾,EventBus將會(huì)發(fā)送NoSubscriberEvent這個(gè)事件,業(yè)務(wù)上可以接收處理光涂。
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
postSingleEventForEventType根據(jù)event類型從subscriptionsByEventType獲取所有訂閱者庞萍,對(duì)每個(gè)訂閱者執(zhí)行postToSubscription。
訂閱方法各有執(zhí)行線程的要求忘闻,postToSubscription其實(shí)就是對(duì)各個(gè)線程模型的分開(kāi)處理钝计,下面分析常用的POSTING、MAIN和BACKGROUND齐佳。
POSTING
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
POSTING私恬,在哪個(gè)線程發(fā)送,就在哪個(gè)線程處理事件炼吴,直接反射invoke本鸣。
MAIN
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
如果當(dāng)前已經(jīng)在UI線程,直接調(diào)用invokeSubscriber硅蹦,否則調(diào)用mainThreadPoster將event入隊(duì)荣德。
前面分析了AndroidHandlerMainThreadSupport保存了UI線程的Looper,通過(guò)Looper創(chuàng)建HandlerPoster童芹,mainThreadPoster正是HandlerPoster的對(duì)象涮瞻。有了UI線程的Handler,接下來(lái)的都是順理成章的代碼假褪。
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
訂閱者信息Subscription和event包裝為PendingPost署咽,通過(guò)next字段,多個(gè)PendingPost構(gòu)建隊(duì)列PendingPostQueue生音。
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
通過(guò)發(fā)送空message宁否,切換線程到UI線程,從隊(duì)列中取出event調(diào)用invokeSubscriber久锥。注意到家淤,在UI線程有執(zhí)行時(shí)長(zhǎng)限制,超時(shí)會(huì)拋出異常瑟由。
BACKGROUND
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
- 如果事件在UI線程中發(fā)布絮重,那么該事件就會(huì)在新的線程中運(yùn)行
- 如果事件在子線程中發(fā)布冤寿,那么該事件直接在發(fā)布事件的線程中執(zhí)行
BackgroundPoster處理事件在新線程中的運(yùn)行,同樣的創(chuàng)建PendingPost并入隊(duì)青伤。
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
線程池從EventBus對(duì)象獲取督怜,看定義,是一個(gè)線程數(shù)幾乎無(wú)限制的CachedThreadPool狠角。
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
最終在線程池的執(zhí)行過(guò)程也是PendingPost出隊(duì)号杠,調(diào)用invokeSubscriber。(代碼嵌套很深7岣琛)
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
后記
EventBus源碼沒(méi)有太難的地方姨蟋,快速通過(guò)。