• 仿EventBus做一个简单的基于订阅发布的事件总线


    一、概述

      在上一节分析了EventBus的源代码。本节仿照EventBus自己做一个事件总线框架,去掉了一些代码,只保留了核心框架,旨在梳理框架的框架原理,加深对框架流程的理解。

      在贴出源代码之前先把这个自定义的EventBus的功能介绍一下。核心流程还是三个,注册、发布、取消注册(未写AnnotationProcessor部分,如果有需要大家可以自己实现),源码中的类绝大部分分仿照了EventBus原有的类名,只是类里面的内容做了简化调整。如:EventBus类只抽离了、post、register、unregister、subscribe方法等。

      完整源代码下载地址

      下面贴出library结构

      

     自己实现的框架其用法和EventBus还是一样的,只是不能发送黏性事假和定义事件的优先级,使用实例代码如下:

    public class MainActivity extends AppCompatActivity {
        private Button btn;
        private TextView tv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            /**
             * 注册观察者对象
             */
            EventBus.getDefault().register(this);
            btn = findViewById(R.id.main_btn);
            tv = findViewById(R.id.main_tv);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    toPost();
                }
            });
    
        }
    
        /**
         * 用于接收post发送过来的事件
         *
         * @param event 具体的事件主体
         */
        @Subscribe
        public void onMessageEvent(MessageEvent event) {
            switch (event.getArg1()) {
                case 0:
                    tv.setText("接收小消息为:" + event.getMsg());
                    break;
    
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            /**
             * 取消订阅
             */
            EventBus.getDefault().unRegister(this);
        }
    
        /**
         * 发送消息
         */
        public void toPost() {
            MessageEvent event = new MessageEvent();
            event.setArg1(0);
            event.setMsg("杨洛峋小宝宝来了");
            EventBus.getDefault().post(event);
        }
    
    }
    

     

    二、源码介绍以及源码截图

      下面提出关键源代码

      EventBus.getDefault().register(subscriber)

      /**
         * 注册
         * 订阅方法
         *
         * @param subscriber
         */
        public void register(Object subscriber) {
            Class clazz = subscriber.getClass();
            List<SubscriberMethod> subscriberMethods = SubscriberMethodFinder.findSubscriberMethods(clazz);
            if (subscriberMethods != null && subscriberMethods.size() > 0) {
                for (SubscriberMethod subscriberMethod : subscriberMethods) {
                    subscribe(subscriber, subscriberMethod);
                }
            }
        }
    
        /**
         * 真正的订阅
         *
         * @param subscriber
         * @param subscriberMethod
         */
        private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
            Class eventType = subscriberMethod.getEventType();
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            }
            int size = subscriptions.size();
            for (int i = 0; i <= size; i++) {
                if (i == size) {
                    //向订阅集合中加入订阅
                    subscriptions.add(i, newSubscription);
                    break;
                }
            }
    
            List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
            if (subscribedEvents == null) {
                subscribedEvents = new ArrayList<>();
                typesBySubscriber.put(subscriber, subscribedEvents);
            }
            subscribedEvents.add(eventType);
    
        }
    

      EventBus.getDefault().post(eventObj)

     /**
         * 发送事件方法
         *
         * @param eventObj
         */
        public void post(Object eventObj) {
            PostingThreadState postingThreadState = currentPostingThreadState.get();
            List<Object> queue = postingThreadState.getEventQueue();
            queue.add(eventObj);
            postingThreadState.setMainThread(isMainThread());
            //缺少一个发送事件的线程
            Class<?> clazz = eventObj.getClass();
            List<Subscription> subscriptions = subscriptionsByEventType.get(clazz);
            if (subscriptions != null) {
                //循环遍历Subscriptions,
                for (Subscription subscription : subscriptions) {
                    //分发事件
                    postToSubscription(subscription, eventObj, postingThreadState);
    
                }
            }
    
        }
    
        /**
         * 返回true为主线程,否则为子线程
         *
         * @return
         */
        private boolean isMainThread() {
            return Looper.myLooper() == Looper.getMainLooper();
        }
    
        /**
         * 对事件进行分发
         *
         * @param subscription
         * @param eventTypeObj
         */
        private void postToSubscription(Subscription subscription, Object eventTypeObj, PostingThreadState postingThreadState) {
            switch (subscription.getSubscriberMethod().getThreadMode()) {
                case POSITION:
                    invokeSubscriber(subscription, eventTypeObj);
                    break;
                case MAIN:
                    if (isMainThread()) {
                        invokeSubscriber(subscription, eventTypeObj);
                    } else {
                        mainThreadHandlerPoster.enqueue(subscription, eventTypeObj);
                    }
                    break;
                case MAIN_ORDERD:
                    if (mainThreadHandlerPoster != null) {
                        mainThreadHandlerPoster.enqueue(subscription, eventTypeObj);
                    } else {
                        invokeSubscriber(subscription, eventTypeObj);
                    }
                    break;
                case BACKGROUND:
                    if (backgroundPoster != null) {
                        backgroundPoster.enqueue(subscription, eventTypeObj);
                    } else {
                        invokeSubscriber(subscription, eventTypeObj);
                    }
                    break;
                case ASYNC:
                    asyncPoster.enqueue(subscription, eventTypeObj);
                    break;
            }
        }
    
        /**
         * 执行事件的具体方法
         *
         * @param subscription
         * @param eventTypeObj
         */
        public void invokeSubscriber(Subscription subscription, Object eventTypeObj) {
            try {
                subscription.getSubscriberMethod().getMethod().setAccessible(true);
                subscription.getSubscriberMethod().getMethod().invoke(subscription.getSubscriber(), eventTypeObj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    

      EventBus.getDefault().unRegister(subscriber)

     /**
         * 取消注册方法
         * 取消注册其实就清除两个 集合就行了,一个是Subscriptions集合,一个是typesBySubscriber集合
         *
         * @param subscriber
         */
        public void unRegister(Object subscriber) {
            List<Class<?>> eventTypes = typesBySubscriber.get(subscriber);
            if (eventTypes != null) {
                for (Class<?> clazz : eventTypes) {
                    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(clazz);
                    for (Subscription subscription : subscriptions) {
                        if (subscriber == subscription.getSubscriber()) {
                            subscriptions.remove(subscription);
                        }
                    }
                }
                typesBySubscriber.remove(subscriber);
            }
    
        }
    

      完整的源代码我发布到了github上欢迎大家下载,地址如下:myeventbuslib

  • 相关阅读:
    SQL Server执行计划的理解
    SQL Server Profiler工具
    利用SQL Profiler处理开销较大的查询
    查询开销
    详解索引连接类型
    详解执行计划
    数据库引擎调整顾问
    six.moves的用法
    ※数据结构※→☆非线性结构(tree)☆============二叉树 顺序存储结构(tree binary sequence)(十九)
    C++ 线程的创建,挂起,唤醒,终止
  • 原文地址:https://www.cnblogs.com/tony-yang-flutter/p/12463490.html
Copyright © 2020-2023  润新知