EventBus學(xué)習(xí)筆記

如果對EventBus原理不太熟悉的童鞋可以看這個:

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);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容