研究了EventBus源码,不贴分析过程,有兴趣的同学自己查看阅读,这才是真程序员(PS:真不是我不擅长写文档,真的呦)。
源码地址:https://github.com/greenrobot/EventBus
官方文档地址:http://greenrobot.org/eventbus/
1. EventBus有几种ThreadMode:
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);
}
}
POSTING:默认模式,表示在当前线程执行
MAIN:在主线程中执行,如果post事件发生是主线程,则直接调用,如果不是,在使用handler进行处理
BACKGROUND:在线程池中执行
ASYNC:在线程池中执行
BackgroundThread与Async的区别:
a. BackgroundThread会判断是否是主线程,是主线程会调用线程池来解决,不是主线程则直接在BackgroundThread当前线程中调用;而Async都会在线程池中调用。
b. BackgroundThread的任务会在线程池中顺序执行(一次只能执行一个),而Async在没有限制。
下面看看backgroundPoster与asyncPoster的源码就知道了:
background:
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);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
//如果queue中没有数据,则等待1s中之后再取。因为线程执行是无须的
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) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
async:
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
答:newCachedThreadPool,自己体会
3. 各个ThreadMode都会使用PendingPostQuene存取PendingPost,如何保证之间不会去错?
答:HandlerPoster(Main),BackgroundPoster(background),AsyncPoster(async)各生成一个PendingPostQuene。
4. EventBus工作原理?
答:当register时,根据注解把相关方法(一个参数,public,非static,非abstract)放到map中(当前类与所有方法参数的map、方法参数与所有方法的map);
当unregister时,还是贴代码吧,手写容易产生误解:
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
//得到当前参数的所有方法(subscriptionsByEventType:方法参数与所有方法的map)
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
//subscription中有两个对象,一个是当前类对象:subscriber;另一个是注册的方法对象
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
//得到当前类的所有方法参数(typesBySubscriber:当前类与所有方法参数的map)
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
//把方法参数从“方法参数与所有方法的map”中删除,见上面方法
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
当post时,根据参数类型,得到所有的方法,通过反射调用。
5. sticky是什么gui?
答:当给方法A用sticky注解时,会立即根据A的方法参数去查找stickyEvents(一个map,参数class为key,参数为value,在postSticky是放入数据)里面的数据,找到了就直接调用A方法,可通过removeStickyEvent需要移除map里的数据,根据需要使用。
6. 其他的各种配置什么含义?
答:偷个图(一般使用默认的就可以)
7. 怎么使用?
答:就不告诉你