EventBus学习笔记

如果对EventBus原理不太熟悉的童鞋可以看这个:

EventBus 原理解析

1.极其简单的订阅-发布-接收模式

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);
    }
}

这是一个极其粗糙的订阅发送的例子,完全不能用于生产。

Q:如果有多个订阅者,每个订阅者也有多种感兴趣事件,怎么做到在发送某种事件时,只触发该事件的接收?

A:接收的方法可自行定义,唯一的参数就是发送的事件,添加指定注解(@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();
                //方法的参数类型
                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:使用到了什么设计模式?

A:有两处使用了享元设计模式,使用缓存的对象去处理:
第一处: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;
    }
调用:
 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) {
                //从第一个取出来和最后一个取出来都没区别,享元模式而已
                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个没区别??
            if (pendingPostPool.size() < 10000) {
                pendingPostPool.add(pendingPost);
            }
        }
    }
调用:
@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:多个订阅者多个订阅方法怎么保证事件发送的优先级?

A: 根据注解上的优先级调整map顺序

CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(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;
            }
        }

Q:为什么发送事件时使用队列(PendingPostQueue)?

A:我觉得没必要使用,其他童鞋能解释下吗?

HandlePoster实现(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;
                //插进去立马就发送消息
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

BackgroundPoster实现(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实现(class AsyncPoster implements Runnable, Poster)

 @Override
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        //可以多次插入多次调用
        eventBus.getExecutorService().execute(this);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269