如果對EventBus原理不太熟悉的童鞋可以看這個:
1.極其簡單的訂閱-發(fā)布-接收模式
public class Publisher {
private Publisher() {
}
public static Publisher getDefault(){
return PublishHoler.sPublisher;
}
public List<ISubScriber> subscribeByEventTypes=new ArrayList<>();
public void register(ISubScriber subScriber){
subscribeByEventTypes.add(subScriber);
}
public void unRegister(ISubScriber subScriber){
subscribeByEventTypes.remove(subScriber);
}
public void post(EventType eventType){
for(ISubScriber subScriber:subscribeByEventTypes){
subScriber.receive(eventType);
}
}
public static class PublishHoler{
private static Publisher sPublisher=new Publisher();
}
}
public interface ISubScriber {
void receive(EventType eventType);
}
public class EventType {
public String message;
public EventType(String message) {
this.message = message;
}
}
public class Subscriber1 implements ISubScriber {
public Subscriber1() {
Publisher.getDefault().register(this);
}
@Override
public void receive(EventType eventType) {
System.out.println(eventType.message);
}
}
這是一個極其粗糙的訂閱發(fā)送的例子,完全不能用于生產(chǎn)。
Q:如果有多個訂閱者,每個訂閱者也有多種感興趣事件,怎么做到在發(fā)送某種事件時,只觸發(fā)該事件的接收?
A:接收的方法可自行定義,唯一的參數(shù)就是發(fā)送的事件,添加指定注解(@Subscribe)方便注冊時反射查找。
@Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 2)
public void onMessageEvent(NotifyMessage event) {
System.out.println(event.message);
}
//源碼里面查找注解
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//todo 找本類的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
//todo 找本類以及父類的所有公共方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
//方法的參數(shù)類型
if (parameterTypes.length == 1) {
//找到方法上的注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//事件類型就是我們MessageEvent
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 (....){
}
}
}
Q:使用到了什么設(shè)計模式?
A:有兩處使用了享元設(shè)計模式,使用緩存的對象去處理:
第一處:FindState
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();
}
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;
}
調(diào)用:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
......省略....
return getMethodsAndRelease(findState);
}
第二處:PendingPost
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
Object event;
Subscription subscription;
PendingPost next;
private PendingPost(Object event, Subscription subscription) {
this.event = event;
this.subscription = subscription;
}
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
//從第一個取出來和最后一個取出來都沒區(qū)別,享元模式而已
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely 這里寫10000和寫4個沒區(qū)別??
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
調(diào)用:
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
..........
}
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
Q:多個訂閱者多個訂閱方法怎么保證事件發(fā)送的優(yōu)先級?
A: 根據(jù)注解上的優(yōu)先級調(diào)整map順序
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
..............
//按照優(yōu)先級對新加入的訂閱同一事件的訂閱者進行排序
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;
}
}
Q:為什么發(fā)送事件時使用隊列(PendingPostQueue)?
A:我覺得沒必要使用,其他童鞋能解釋下嗎?
HandlePoster實現(xiàn)(public class HandlerPoster extends Handler implements Poster)
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
//插進去立馬就發(fā)送消息
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
BackgroundPoster實現(xiàn)(final class BackgroundPoster implements Runnable, Poster)
@Override
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);
}
}
}
AsyncPoster實現(xiàn)(class AsyncPoster implements Runnable, Poster)
@Override
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
//可以多次插入多次調(diào)用
eventBus.getExecutorService().execute(this);
}