Eventbus3代码分析(五):getDefault(),register和EventBusBuilder等


EventBus getDefault()入口

除了注解,其他都和EventBus这个类有关系了 我们先从getDefault()方法开始分析


入口分析

这里的getDefault()静态方法,很容易看出,是一个 线程加锁的懒汉单例 具体通过new EventBus() 来创建实例

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

具体EventBus()构造

我们可以发现,具体的构造,其实是 初始化一些Map值,引用类,EventBusBuilder中的实现传递给EventBus类 其他的类,慢慢分析

EventBus(EventBusBuilder builder) {
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
}

这里EventBusBuilder,只是一个 饿汉单例 在类创建之前,就已经创建出来了

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

而构造的赋值,只是把 Builder中的值传递到本类中


对应的EventBusBuilder对象

我们观察下面对应的EventBusBuilder类 有1个默认的线程池,管理线程 有很多boolean类型的变量,存储默认boolean属性 有2个List,分别存储Class<?>类型 和 EventBusBuilder

public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;
    boolean logNoSubscriberMessages = true;
    boolean sendSubscriberExceptionEvent = true;
    boolean sendNoSubscriberEvent = true;
    boolean throwSubscriberException;
    boolean eventInheritance = true;
    boolean ignoreGeneratedIndex;
    boolean strictMethodVerification;
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
    List<Class<?>> skipMethodVerificationForClasses;
    List<SubscriberInfoIndex> subscriberInfoIndexes;

    EventBusBuilder() {
    }

    /** Default: true */
    public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
        this.logSubscriberExceptions = logSubscriberExceptions;
        return this;
    }

    /** Default: true */
    public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
        this.logNoSubscriberMessages = logNoSubscriberMessages;
        return this;
    }

    /** Default: true */
    public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
        this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
        return this;
    }

    /** Default: true */
    public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
        this.sendNoSubscriberEvent = sendNoSubscriberEvent;
        return this;
    }

    /**
     * Fails if an subscriber throws an exception (default: false).
     * <p/>
     * Tip: Use this with BuildConfig.DEBUG to let the app crash in DEBUG mode (only). This way, you won't miss
     * exceptions during development.
     */
    public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
        this.throwSubscriberException = throwSubscriberException;
        return this;
    }

    /**
     * By default, EventBus considers the event class hierarchy (subscribers to super classes will be notified).
     * Switching this feature off will improve posting of events. For simple event classes extending Object directly,
     * we measured a speed up of 20% for event posting. For more complex event hierarchies, the speed up should be
     * >20%.
     * <p/>
     * However, keep in mind that event posting usually consumes just a small proportion of CPU time inside an app,
     * unless it is posting at high rates, e.g. hundreds/thousands of events per second.
     */
    public EventBusBuilder eventInheritance(boolean eventInheritance) {
        this.eventInheritance = eventInheritance;
        return this;
    }


    /**
     * Provide a custom thread pool to EventBus used for async and background event delivery. This is an advanced
     * setting to that can break things: ensure the given ExecutorService won't get stuck to avoid undefined behavior.
     */
    public EventBusBuilder executorService(ExecutorService executorService) {
        this.executorService = executorService;
        return this;
    }

    /**
     * Method name verification is done for methods starting with onEvent to avoid typos; using this method you can
     * exclude subscriber classes from this check. Also disables checks for method modifiers (public, not static nor
     * abstract).
     */
    public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
        if (skipMethodVerificationForClasses == null) {
            skipMethodVerificationForClasses = new ArrayList<>();
        }
        skipMethodVerificationForClasses.add(clazz);
        return this;
    }

    /** Forces the use of reflection even if there's a generated index (default: false). */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
        return this;
    }

    /** Enables strict method verification (default: false). */
    public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) {
        this.strictMethodVerification = strictMethodVerification;
        return this;
    }

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if(subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

    /**
     * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be
     * done only once before the first usage of the default EventBus.
     *
     * @throws EventBusException if there's already a default EventBus instance in place
     */
    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

    /** Builds an EventBus based on the current configuration. */
    public EventBus build() {
        return new EventBus(this);
    }

}

这里,看上去代码很多 大多数都是设置boolean值的方法 一个设置 线程池 ExecutorService的方法 一个 给List 添加 Class<?> 的 skipMethodVerificationFor方法 一个给List添加SubscriberInfoIndex类型对象的 addIndex 方法 另外有 初始化外面EventBus对象的 installDefaultEventBus() 和 build() 方法

总体,就是设置boolean值,添加List对象的一个类


register(Object subscriber) 和 unregister(Object subscriber)

在外部使用的时候,我们最直接的,除了getDefault()这个单例以外 就是 register 和 unregister了

register

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

代码内容,也很好理解

  • 通过传入的类(Activity中,一般写的是this,也就是Activity本身)
  • 得到对应的 Class<?> 对象, 再通过 SubscriberMethodFinder对象(下一篇一起分析这个类)去得到 一个 SubscriberMethod的List
  • 把对应的List放入到一个容器中(应该用于之后通知的过程中,判断是否响应)

unregister

/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

这里也比较好理解,通过容器,拿到对应的Class<?> 的List 也就是某个Activity或者Fragment中,对应的注解类型 循环去遍历,最后在容器Map<Object, List<Class<?>>> typesBySubscriber 中 remove掉对应的key,也就是Activity或者Fragment中所有注解的方法


post方法

我们知道,对应的值,是通过post去完成的 这里 用 ThreadLocal的线程包装类,去完成对应的线程记录和操作 对应的泛型PostingThreadState对象,记录对应的信息,将对应的线程放入一个List中 通过对应的状态,判断Looper.getMainLooper() == Looper.myLooper() 是否是主线程等操作, 将状态存入PostingThreadState的属性中 最后,遍历容器中的Event, 最后通过存储的Subscription中的subscriberMethod的method,反射去invoke调用方法。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

HUST 1017 - Exact cover

Time Limit: 15s Memory Limit: 128MB Special Judge Submissions: 7636 Solved: 38...

33770
来自专栏小灰灰

Greenrobot-EventBus源码学习(四)

EventBus 深入学习四之实例&类说明 本篇开始,则转向greenrobot/EventBus, 之前基本上将Guava中设计的思路捋了一遍,逻辑比较简...

44890
来自专栏小灰灰

Greenrobot-EventBus源码学习(五)

EventBus 深入学习五之注册 订阅者的注册 + 消息推送 1. 注册 先贴出注册代码, 可以可到和 Guava 相比没什么大的区别, 主要的点在内部实...

24160
来自专栏数据结构与算法

各种数论模板 不断更新 绝对精品

1.筛法求素数 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #inclu...

35290
来自专栏数据结构与算法

BZOJ1576: [Usaco2009 Jan]安全路经Travel(最短路 并查集)

给你一张无向图,保证从1号点到每个点的最短路唯一。对于每个点求出删掉号点到它的最短路上的最后一条边(就是这条路径上与他自己相连的那条边)后1号点到它的最短路的长...

8210
来自专栏数据结构与算法

PE刷题记

开始以为有单调性,也就是如果长度为$x$的能构成素数,那$x - 1$一定能构成素数

11940
来自专栏张善友的专栏

Temp权限引起的WCF问题

WCF按照BasicHttpBinding方式发布,部署到服务器上,再在其他项目中引用的时候,就会出现不能正确下载元数据的错误。使用svcutil.exe工具进...

202100
来自专栏小樱的经验随笔

“玲珑杯”ACM比赛 Round #13 题解&源码

A ? 题目链接:http://www.ifrog.cc/acm/problem/1111 分析:容易发现本题就是排序不等式, 将A数组与B数组分别排序之后,...

31140
来自专栏数据结构与算法

洛谷P1351 联合权值(树形dp)

9020
来自专栏曾大稳的博客

队列(Queue)

看看队列在Android里面的使用 Handle消息队列 使用Handle的时候都要使用Looper.loop()

32920

扫码关注云+社区

领取腾讯云代金券