EventBus的使用这里就不讲了,从几个问题来分析源码吧
1:subscribe 注解的方法如何读取,并维护数据
2:post后如何找到对应的方法
3:线程间如何切换
先举个栗子
public class Test1 {
private final String TAG = getClass().getSimpleName();
public Test1() {
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void test1Fun(TestEvent event) {
Log.e(TAG," --- test1Fun ---- event=" + event);
}
@Subscribe(threadMode = ThreadMode.ASYNC)
public void test2Fun(TestEvent2 event) {
Log.e(TAG," --- test1Fun ---- event=" + event);
}
public void destroy() {
EventBus.getDefault().unregister(this);
}
}
这个是大家常用的写法。后面就直接以这个栗子来说明了。
一:subscribe 注解的方法如何读取,并维护数据
EventBus里面有2个变量:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
该变量存储了某个参数对应的所有的注解方法
key:方法的类型 TestEvent.class,value: 所有方法类型的集合
List<> {
Subscription(test1, new SubscriberMethod(test1Fun.Method, ThreadMode.MAIN, TestEvent.class,xx)),
}
key:方法的类型 TestEvent2.class,value: 所有方法类型的集合
List<> {
Subscription(test1, new SubscriberMethod(test2Fun.Method, ThreadMode.MAIN, TestEvent2.class,xx)),
}
也就是说监听TestEvent消息的方法类型(test1Fun)都存在了subscriptionsByEventType中了。后续post消息时,会从subscriptionsByEventType中查找方法类型。
final class Subscription {
final Object subscriber;//调用regiest的类的引用,如test1
final SubscriberMethod subscriberMethod;
}
public class SubscriberMethod {
final Method method; //被注解的方法 如上面的Test1Fun
final ThreadMode threadMode; //线程模型
final Class<?> eventType; //参数类型,如上面的TestEvent
final int priority;
final boolean sticky;
/**
* Used for efficient comparison
*/
String methodString;
}
private final Map<Object, List<Class<?>>> typesBySubscriber; //存储了某个类下面的所有注释的参数<test1,List<Parmas.class>>
key:调用regiest的类 test1,value:所有方法类型的集合
List<>{
TestEvent.class,
TestEvent2.class
}
typesBySubscriber是用来检测类是否被regeist过,或在unregiest时清理该类下面所有的方法。
2:post后如何找到对应的方法
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;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
...........................................
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//找到该event类的所有父类和接口
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);
}
..........................................
}
通过lookupAllEventTypes找到event所有的父类和接口,也就是说发送的消息也会发送给他的父类和接口,
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;
........................
}
从subscriptionsByEventType中取出了eventClass所对应的方法,然后一个一个的往该方法中丢数据。这里就能看出他是怎么知道对应的post方法。
3:线程间如何切换
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 MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(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);
}
}
postToSubscription判断运行的线程,然后对不同的线程做对POST来说直接调用invokeSubscriber
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);
}
}
我们能看到是通过反射的方法去调用的。
而主线的处理则是在mainThreadPoster里面处理的。
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
.................................
}
}
@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;
}
}
}
........................
}
} finally {
handlerActive = rescheduled;
}
}
}
HandlerPoster其实是运行在主线程的handler,所以在handleMessage中运行的方法都是在主线程中执行的。
后台线程backgroundPoster。就是一个运行在线程池中的Runnable。
final class BackgroundPoster implements Runnable, Poster {
...................
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) {
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);
.............................
}
}
asyncPoster和backgroundPoster一样,也是一个runnable 不同的是backgroundPoster的线程可以复用,当 executorRunning=true的时候就不会开启新的线程。而asyncPoster每次都会开启新线程。
class AsyncPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
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);
}
}
至此3个问题已经讲解完毕