Morecoin powershell dictionary jpa request Movejs vue router 郑州网络 android经典项目开发实战 pmp视频教程 外卖系统源码 maven插件 python正则匹配中文 java文件 java配置 java最新框架 java开发环境安装 java方法重载 java学习平台 java数组输出 java安装教程 java字符串格式化 java重命名 java获取当前日期 java文件复制 java环境下载 登录界面html matlab2016a安装教程 win10计算器下载 电脑手机模拟器 ram容量是什么意思 工信部手机入网查询 原创检测工具 movavi js代码混淆工具 babelrc 网络驱动 电脑还原软件 oledbconnection 加速软件
当前位置: 首页 > 学习教程  > 编程语言

EventBus源码解析

2021/2/13 17:21:24 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

第一步&#xff1a;register 注册一个eventbus EventBus.getDefault().register(this) public void register(Object subscriber) {Class<?> subscriberClass subscriber.getClass();List<SubscriberMethod> subscriberMethods subscriberMethodFinder.findSu…

第一步:register

注册一个eventbus

EventBus.getDefault().register(this)

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

1.拿到注册对象的class,通过该对象找到所有添加了@Subscribe注解的方法

  private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            try {
                methods = findState.clazz.getMethods();
            } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
                String msg = "Could not inspect methods of " + findState.clazz.getName();
                if (ignoreGeneratedIndex) {
                    msg += ". Please consider using EventBus annotation processor to avoid reflection.";
                } else {
                    msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
                }
                throw new EventBusException(msg, error);
            }
            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) {
                        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 (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

首先通过 findState.clazz拿到订阅者的所有方法,遍历找出带有@Subscribe注解的方法

这里会判断方法必须为public,参数只能为一个,否则就会报错然后拿到方法中第一个参数

的参数类型class,threadMode,priority,sticky等信息,封装到一个SubscriberMethod对象中,

再把该对象add到一个集合里,这样findState里的subscriberMethods就存储了所有的订阅方法

拿到这个集合后就开始调用subscribe方法进行订阅

 

第二步:subscribe

订阅事件,post发送过来的事件会进入到此方法

threadMode 该方法执行所在线程,priority,优先级,数值越大,优先级越高,sticky,是否是粘性事件

@Subscribe(threadMode = ThreadMode.MAIN, priority = 100, sticky = true) 
fun test1(text: String) {
      mTextView?.setText(text)
}

 

 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + 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;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
        //暂时先不看粘性事件
    }

1.订阅的核心方法,就是在这个方法中会生成我们常说的那张表,首先看一下参数,subscriber是

调用register时传进来的订阅者对象,subscriberMethod则是由这个订阅者对象里带有@Subscribe注解

的方法的信息封装成的subscriberMethod对象的集合,即subscriberMethod包含了带有@Subscribe注解的

方法的方法名,参数类型,threadMode,priority,sticky等信息

2.首先拿到参数的类型class

然后将subcriber和subscribeMethod封装成了一个Subscription对象,然后通过这个参数class

去一个map里面拿,如果为空就new 一个放进去,看一下这个map

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

它的key是参数的class对象,value是封装了subcriber和subscribeMethod的Subscription类的一个集合,这个

CopyOnWriteArrayList是一个线程安全的ArrayList,当成ArrayList就行。

如果这个集合里不包含newSubscription,就根据优先级将它添加到指定的位置,下面用一张图来表示这个表

还有一张表,它存储了每个注册者里带有注解的方法的参数的类型

可以这样表示,比上面那个要简单一些,之所以要存储成这样的两张表,是因为在反注册的时候,可以根据这些注册者和参数类型去反注册

 

第三步:post

发送事件

EventBus.getDefault().post("text")

/** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

主要看postSingleEvent()方法

 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

event就是我们post()方法中的参数对像,再拿到它的class对象调用postSingleEventForEventType()方法

 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }

这一步就是从我们post的参数类型去map里找到所以参数类型相同的Subscription对象,就是从第一张表中根据参数类型key

找到该参数类型所对应的所有封装了subcriber和subcriberMethod的Subscription集合,对它进行遍历,根据指定的不同运行线程

做处理

 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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }

01.POSTING:接收和发送在同一个线程,不管你是主线程还是子线程

02.MAIN:如果是主线程发送的,直接运行,如果是在子线程发送的,则需要通过Handler切换到主线程来接收

03.MAIN_ORDER:这个是新加的一种模式,按照事件的发送顺序来执行,线程关系和02一样

04.BACKGROUND:如果是主线程,就开启一个子线程来执行,如果是子线程,就在该子线程中执行

05:ASYNC:始终开启一个另外的子线程执行

最后就是调用之前存入到subscription.subscriberMethod中的method的invoke来反射执行方法,这样一次post过程就完成了

 void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

第四步:unregister

反注册eventbus,防止内存泄漏

EventBus.getDefault().unregister(this)

反注册就很简单了,主要是将上述两张表里的引用移除,因为EventBus.getDefault()的一个静态的单例,生命周期要比我们的

注册者长,不及时移除的话,注册者就会继续持有eventbus的引用,从而导致内存泄漏。

 /** 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 {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

1.首先通过订阅者的实例对象拿到上述第二张表中的value,遍历该value中的所有方法参数类型class,

2.再通过该class拿到第一张表中的value,遍历这个subcriptions集合,找到里面的subcriber等于我们传入的订阅者的subcriber

将之移除,最后在第一张表中移除该subcriber

 /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

最后再记录一下EventBus中用到的设计模式

1.单例----------构造EventBus对象

2.享元----------FindState的复用

3.Builder----------构造EventBus对象

4.观察者模式----------可以说整个EventBus就是使用的观察者模式构建的,我们注册就是相当于订阅者,每次数据有变化,EventBus就会通知所有的订阅者,从而订阅者做出相应的改变。

学艺不精,可能还有其他的模式没有看出来,大佬轻喷


本文链接: http://www.dtmao.cc/news_show_700126.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?