美文网首页
Android EventBus源码分析

Android EventBus源码分析

作者: 天道__ | 来源:发表于2018-08-26 01:28 被阅读0次

    一、先看看EventBus的简单使用

    1. 导入eventbus
    compile 'org.greenrobot:eventbus:3.0.0'
    
    2. MainActivity
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //首先要在你要接受EventBus的界面注册,这一步很重要
            EventBus.getDefault().register(this);
            Button btnCommon = (Button) findViewById(R.id.btn_common);
            btnCommon.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {          
                case R.id.btn_common:
                    //点击按钮进入CommonActivity
                    CommonActivity.start(this);
                    break;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //在界面销毁的地方要解绑
            EventBus.getDefault().unregister(this);
        }
    
        //任意写一个方法,给这个方法一个@Subscribe注解,参数类型可以自定义,但是一定要与你发出的类型相同
        @Subscribe
        public void getEventBus(Integer num) {
            if (num != null) {
                //这里拿到事件之后吐司一下
                Toast.makeText(this, "num" + num, Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    
    3. CommonActivity
    public class CommonActivity extends AppCompatActivity implements View.OnClickListener {
    
        public static void start(Context context) {
            context.startActivity(new Intent(context, CommonActivity.class));
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_common);
            Button button = (Button) findViewById(R.id.btn_send);
            button.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_send:
                    //点击按钮,发送一个int类型的事件
                    EventBus.getDefault().post(666);
                    finish();
                    break;
            }
        }
    }
    
    
    4. 指定线程执行
    //CommonActivity 里面发送消息放到子线程
    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            EventBus.getDefault().post(666);
                            finish();
                        }
        }).start();
                    
                    
    //MainActivity里面接收事件,只需要指定线程模式即可,即threadMode = ThreadMode.MAIN-->
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getEventBus(Integer num) {
            if (num != null) {
                Toast.makeText(this, "num" + num, Toast.LENGTH_SHORT).show();
            }
    }
    
    
    
    5. Stick Event(黏性事件)

      简单讲,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。
      1. 先发布事件

    //点击按钮,跳转到StickActivity并携带参数,参数类型为String
    EventBus.getDefault().postSticky("我是黏性事件");
    //开启新的activity
    StickActivity.start(this);
    
    

      2. 在订阅事件

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_stick);
            //前面也说了,在任何你要接收事件的地方都要先注册
            EventBus.getDefault().register(this);
    }
        
    //同样的,自定义一个方法,加上 @Subscribe,不同的是在后面再加上一句sticky = true告诉EventBus这是一个粘性事件
    @Subscribe(sticky = true)
    public void getEventBus(String str) {
            Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
    }
    
    

    二、源码分析(EventBus.java)

    1. 看看定义的变量
        // 一看就是单例
        static volatile EventBus defaultInstance;
        // 建造者模式
        private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
        // 类型缓存的集合
        private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
    
        // key 是 Event 参数的类 例如String
        // value 存放的是 Subscription 的集合列表
        // Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象),一个是 SubscriberMethod 注解方法的所有属性参数值
        //  发送消息会遍历此集合
        private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        // key 是所有的订阅者
        // value 是所有订阅者里面方法的参数的class 例如String
        //  主要用于移除订阅者
        private final Map<Object, List<Class<?>>> typesBySubscriber;
        //  发送粘性事件会遍历此集合
        private final Map<Class<?>, Object> stickyEvents;
    
        // 空间换时间 每个线程都有自己的副本
        private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
            @Override
            protected PostingThreadState initialValue() {
                return new PostingThreadState();
            }
        };
    
    2. 看看注册方法
        public void register(Object subscriber) {
            Class<?> subscriberClass = subscriber.getClass();
            // 拿到类的所以的方法(通过反射方法,然后拿到方法上的注解)
            // findSubscriberMethods()去解析注册者对象的所有方法,并且找出带有注解 Subscribe注解的的方法,然后通过Annotation解析所有细节参数(threadMode,priority,sticky,eventType,method),把这些参数封装成一个 SubscriberMethod,添加到集合返回。
            List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
            synchronized (this) {
                for (SubscriberMethod subscriberMethod : subscriberMethods) {
                    // 将activity 和注解的方法一一绑定
                    subscribe(subscriber, subscriberMethod);
                }
            }
        }
    
    3. 看看反射方法的实现
        private void findUsingReflectionInSingleClass(FindState findState) {
           
            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();
                                // 讲方法上的注解 封装成一个对象 ,存放到集合里面List<SubscriberMethod>
                                findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                        subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                            }
                        }
                    }
        }
    
    4. 在看看怎么绑定的

    // subscriptionsByEventType
    // 第一步 讲acitivty 和方法封装成一个对象
    // 第二步 讲方法类型 作为key 不同的activity和方法做一个对象放到一个集合里面
    // 第三步 按照当前方法的优先级进行集合的存放

    // typesBySubscriber
    // 将Actvitity作为key eventType存放到一个集合,然后存放到typesBySubscriber

        // Must be called in synchronized block
        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++) {
            // 存放activity +type  按照优先级排序
                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);
    
           
        }
    
    5. 简单的例子(subscriptionsByEventType)

      将Event的参数类型作为Key,Subscription的集合列表作为Value。然后在post发送内容的时候依据参数的类型去寻找对应的注册者 ,执行对象的方法。结构如下(伪代码)。

        // String类型的subscriber
        List<Object> mList=new ArrayList<>();
        mList.add(new Subscription(MainActivity,test1(String)));
        mList.add(new Subscription(MainActivity,test2(String)));
        mList.add(new Subscription(MainActivity2,test2(String)));
    
        // int类型的subscriber
        List<Object> mList1=new ArrayList<>();
        mList1.add(new Subscription(MainActivity,test3(int)));
        mList1.add(new Subscription(MainActivity2,test1(int)));
    
        Map<String,List> map=new HashMap<>();
        map.put("int",mList1);
        map.put("String",mList);
    
    6. 简单的例子 (typesBySubscriber)

      将注册者作为Key,参数类型的集合作为Value。这个参数类型的集合针对的是当前注册者中的。 结构如下(伪代码)

        List<Object> mList=new ArrayList<>();
        mList.add("String");
        mList.add("int");
    
    
        Map<String,List> map=new HashMap<>();
        map.put("MainActivity",mList);
    
    7. post()核心的发送代码
        public void post(Object event) {
            // currentPostingThreadState 是一个 ThreadLocal,
            // 他的特点是获取当前线程一份独有的变量数据,不受其他线程影响。
            PostingThreadState postingState = currentPostingThreadState.get();
            // postingState 就是获取到的线程独有的变量数据
            List<Object> eventQueue = postingState.eventQueue;
            // 把 post 的事件添加到事件队列
            eventQueue.add(event);
            // 如果没有处在事件发布状态,那么开始发送事件并一直保持发布状态
            if (!postingState.isPosting) {
                // 是否是主线程
                postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                // isPosting = true
                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;
                }
            }
        }
        
        
        
        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);
                    // 依次向 eventClass 的父类或接口的订阅方法发送事件
                    // 只要有一个事件发送成功,返回 true ,那么 subscriptionFound 就为 true
                    subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
                }
            } else {
                subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
            }
           
        }
        
        private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
            CopyOnWriteArrayList<Subscription> subscriptions;
            synchronized (this) {
            // 得到Subscription 列表
                subscriptions = subscriptionsByEventType.get(eventClass);
            }
            if (subscriptions != null && !subscriptions.isEmpty()) {
                for (Subscription subscription : subscriptions) {
                    postingState.event = event;
                    postingState.subscription = subscription;
                    boolean aborted = false;
                    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;
        }
        
        
        
        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);
            }
        }
    
    8. unregister(),

    在unregister()方法中。调用typesBySubscriber,先通过注册者(MainActivity)找到对应的参数类型集合。然后遍历参数类型集合,拿着参数类型去subscriptionsByEventType找对应的Subscriber。如果Subscriber的注册者是参数类型的注册者,直接移除

        /** 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());
            }
        }
    
    9. 看看移除的伪代码
        //第一步 先查找typesBySubscriber Map 得到一个集合
        //传递   MainActivity,查找的是一个list集合 有2个参数类型
        //mList.add("String");
        //mList.add("int");
    
        //第二步 遍历集合, 拿着类型去subscriptionsByEventType查找
        // String 有3个   
        // mList.add(new Subscription(MainActivity, test1(String)));
        // mList.add(new Subscription(MainActivity, test2(String)));
        //mList.add(new Subscription(MainActivity2, test2(String)));
    
        //第三步
        //有2个与MainActivity一样的都移除。剩下
        //mList.add(new Subscription(MainActivity2, test2(String)));
    

    三、手写EventBus

    1. 主要手写EventBus.java
    /**
     * @author 512573717@qq.com
     * @created 2018/8/26  上午1:21.
     */
    public class EventBus {
        // subscriptionsByEventType 这个集合存放的是?
        // key 是 Event 参数的类  例如MainActivity里面的 test(String) String
        // value 存放的是 Subscription 的集合列表
        // Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象),一个是 SubscriberMethod 注解方法的所有属性参数值
        private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
        // typesBySubscriber 这个集合存放的是?
        // key 是所有的订阅者   MainActivity
        // value 是所有订阅者里面方法的参数的class 例如MainActivity里面的 test(String) String
        private final Map<Object, List<Class<?>>> typesBySubscriber;
    
        private EventBus() {
            typesBySubscriber = new HashMap<Object, List<Class<?>>>();
            subscriptionsByEventType = new HashMap<>();
        }
    
        static volatile EventBus defaultInstance;
    
        /**
         * Convenience singleton for apps using a process-wide EventBus instance.
         */
        public static EventBus getDefault() {
            if (defaultInstance == null) {
                synchronized (EventBus.class) {
                    if (defaultInstance == null) {
                        defaultInstance = new EventBus();
                    }
                }
            }
            return defaultInstance;
        }
    
        public void register(Object object) {
            // 1. 解析所有方法封装成 SubscriberMethod 的集合
            List<SubscriberMethod> subscriberMethods = new ArrayList<>();
            Class<?> objClass = object.getClass();
            Method[] methods = objClass.getDeclaredMethods();
            for (Method method : methods) {
                //解析所有带有注解的方法
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                if (subscribe != null) {
                    // 所有的Subscribe属性 解析出来
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    SubscriberMethod subscriberMethod = new SubscriberMethod(
                            method, parameterTypes[0], subscribe.threadMode(), subscribe.priority(), subscribe.sticky());
                    subscriberMethods.add(subscriberMethod);
                }
            }
            // 2. 按照规则存放到 subscriptionsByEventType 里面去
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscriber(object, subscriberMethod);
            }
        }
    
        // 2. 按照规则存放到 subscriptionsByEventType 里面去
        private void subscriber(Object object, SubscriberMethod subscriberMethod) {
            Class<?> eventType = subscriberMethod.eventType;
            // 随处能找到,我这个代码
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            }
    
            // 判断优先级 (不写)
            Subscription subscription = new Subscription(object, subscriberMethod);
            subscriptions.add(subscription);
    
            // typesBySubscriber 要弄好是为了方便移除
            List<Class<?>> eventTypes = typesBySubscriber.get(object);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                typesBySubscriber.put(object, eventTypes);
            }
            if (!eventTypes.contains(eventType)) {
                eventTypes.add(eventType);
            }
        }
    
        public void unregister(Object object) {
            List<Class<?>> eventTypes = typesBySubscriber.get(object);
            if (eventTypes != null) {
                for (Class<?> eventType : eventTypes) {
                    removeObject(eventType, object);
                }
            }
        }
    
        private void removeObject(Class<?> eventType, Object object) {
            // 获取事件类的所有订阅信息列表,将订阅信息从订阅信息集合中移除,同时将订阅信息中的active属性置为FALSE
            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 == object) {
                        // 将订阅信息从集合中移除
                        subscriptions.remove(i);
                        i--;
                        size--;
                    }
                }
            }
        }
    
        public void post(Object event) {
            // 遍历 subscriptionsByEventType,找到符合的方法调用方法的 method.invoke() 执行。要注意线程切换
            Class<?> eventType = event.getClass();
            // 找到符合的方法调用方法的 method.invoke() 执行
            CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions != null) {
                for (Subscription subscription : subscriptions) {
                    executeMethod(subscription, event);
                }
            }
        }
    
        private void executeMethod(final Subscription subscription, final Object event) {
            ThreadMode threadMode = subscription.subscriberMethod.threadMode;
            boolean isMainThread = Looper.getMainLooper() == Looper.myLooper();
            switch (threadMode) {
                case POSTING:
                    invokeMethod(subscription, event);
                    break;
                case MAIN:
                    if (isMainThread) {
                        invokeMethod(subscription, event);
                    } else {
                        // 行不行,不行?行?
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                invokeMethod(subscription, event);
                            }
                        });
                    }
                    break;
                case ASYNC:
                    AsyncPoster.enqueue(subscription, event);
                    break;
                case BACKGROUND:
                    if (!isMainThread) {
                        invokeMethod(subscription, event);
                    } else {
                        AsyncPoster.enqueue(subscription, event);
                    }
                    break;
            }
        }
    
        private void invokeMethod(Subscription subscription, Object event) {
            try {
                subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    2. 调用(MainActivity)
     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 注册,思考为什么要注册?
            EventBus.getDefault().register(this);
    
            // 进入测试界面
            mTv = (TextView) findViewById(R.id.test_tv);
            mTv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, TestActivity.class);
                    startActivity(intent);
                }
            });
    
    
        }
    
      /**
         * threadMode 执行的线程方式
         * priority 执行的优先级
         * sticky 粘性事件
         */
        @Subscribe(threadMode = ThreadMode.MAIN, priority = 50, sticky = true)
        public void test1(String msg) {
            // 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
            Log.e("TAG", "msg1 = " + msg);
            mTv.setText(msg);
        }
        
         @Override
        protected void onDestroy() {
            // 解绑,思考为什么要解绑?
            EventBus.getDefault().unregister(this);
            super.onDestroy();
        }
    
    3. 调用(TestActivity)
    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findViewById(R.id.test_tv).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    EventBus.getDefault().post("text");
                }
            });
        }
    
    4. 执行结果
    29731-29731/demo.dhcc.com.eventbusdemo E/TAG: msg1 = text
    
    4. 总结

      主要的是使用反射,存储app中所有注册过的activity或者Fragment,在发生消息的时候去遍历这个map执行响应的方法。

    相关文章

      网友评论

          本文标题:Android EventBus源码分析

          本文链接:https://www.haomeiwen.com/subject/ecpniftx.html