IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android EventBus保姆级源码解析(一)注册方法register -> 正文阅读

[移动开发]Android EventBus保姆级源码解析(一)注册方法register

记得上次写EventBus还是在上次(一年前,哈哈),转眼间又是一年了,发现对于EventBus的源码细节有点模糊,挖个坑捋捋EventBus的源码

由于项目中使用且当前最新版本源码变化不大,本文贴出的源码基于EventBus3.0.0,关于EventBus的用法可以移步我之前的文章:

Android EventBus你需要了解的都在这

EventBus.register

首先,EventBus的原理是基于发布订阅模式,有些萌新开始会以为是观察者模式,其实它跟观察者模式的区别在于不需要观察者(订阅者)和目标(发布者)直接交互,而是通过调度中心来进行分发事件,实现了它们之间的解耦。

看源码首先可以从我们使用的第一步,注册订阅事件的方法register开始:

   /**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * <p/>
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

其中

  • SubscriberMethodFinder是EventBus用来管理订阅事件的方法类
  • SubscriberMethod是EventBus的订阅方法(使用@Subscribe注解的方法),其中封装了订阅者的回调方法、线程模式、EventClass、是否为粘性事件等信息

EventBus通过传入的Object对象subscriber的class,构造出了一个SubscriberMethod数组,看看构造数组的findSubscriberMethods方法中有什么

SubscriberMethodFinder.findSubscriberMethods

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        //如果缓存里有的话直接使用
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        //针对是否忽略继承的索引,采用不同的查找策略
        //通过反射获取Subscriber注解的方法list,这块就不往下跟了,各位有兴趣可以自己看看
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);
        }
        if (subscriberMethods.isEmpty()) {
            throw new EventBusException("Subscriber " + subscriberClass
                    + " and its super classes have no public methods with the @Subscribe annotation");
        } else {
            //如果构造出的subscriberMethods不为空,则放入缓存
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }

简单说,findSubscriberMethods方法中主要是通过反射获取目标类中添加了@Subscriber注解的方法数组

然后register()中会遍历方法数组,调用subscribe方法订阅:

EventBus.subscribe

其中

  • Subscription是包裹订阅类和订阅者信息的包装类
  • SubscriberMethod是上边说过的EventBus的订阅方法,其中封装了订阅者的回调方法、线程模式、EventClass、是否为粘性事件等信息,为了防止各位弄混,再强调一下
  • typesBySubscriber是EventBus中存放的“订阅者-事件类型”列表
   // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        //获取事件类型(EventClass)对应的订阅(订阅者,订阅者方法)list
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
        //指定的事件类型没有对应的观察对象的时候,初始化list再添加进去
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
        //如果同一个类重复订阅同一个事件,抛出EventBusException异常
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }

        int size = subscriptions.size();
        //遍历subscriptions,依据优先级,将新的订阅插入到list中
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        // 从“订阅者-事件类型”列表中尝试获取该订阅者对应的所有事件类型
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        //如果是订阅者的第一个订阅事件,构造一个typesBySubscriber put之后再添加
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        //如果这个事件是黏性事件
        if (subscriberMethod.sticky) {
            //是否判断同类型的超类flag
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                       // post黏性事件
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
               // post黏性事件
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

对于普通事件,添加到subscribedEvents后该时间就处理完毕了,低于黏性事件,则还会使用checkPostStickyEventToSubscription(newSubscription, stickyEvent);方法继续向该观察者通知所有的黏性事件

    //跳过stickyEvent为空的情况
    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
            // --> Strange corner case, which we don't take care of here.
            postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
        }
    }
    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 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);
        }
    }

这里就是post处理事件的逻辑了,
到这里本篇EventBus.register注册方法的解析就结束了,详细的代码解析会放到后续的处理post事件解析

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-16 17:47:32  更:2021-12-16 17:48:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:58:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码