• EventBus猜想 ----手把手带你自己实现一个EventBus


    本文是什么

    本文是一篇怀着推測角度学习一个未知东西(EventBus)的文章。

    1. 先推測EventBus是怎样实现的。
    2. 依据推測去模仿他的实现。
    3. 查看源代码。验证猜想。

      更深入的去理解他。

    转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50628416

    关于EventBus前面已经介绍了他的使用方法。

    退出App新的优雅方式

    依据使用流程猜想

    使用EventBus的流程例如以下:
    1. 注冊EventBus

    EventBus.getDefault().register(this);

    2 . 发送一条消息

     EventBus.getDefault().post("hello eventBus");

    3.处理这条消息

    onEventMainThread()

    原理猜想

    也就是说,你想要接受一条消息,首先必需要先注冊。将本身作为參数传入EventBus。 然后你必须写一个onEvent方法。所以能够推測这里肯定是在post消息的时候 调用了这种方法,因为将本身传入了,所以这种方法能够用反射来调用。

    猜想实现

    呃。已经有了猜想,那么来实现下面我们这个步骤。


    首先新建一个类。叫做EventBusLite。把他弄成单例模式

    public class EventBusLite {
    
        private static EventBusLite mEventBus;
        private EventBusLite(){
    
        }
    
        public static EventBusLite getDefault(){
            if(mEventBus == null){
                mEventBus = new EventBusLite();
            }
            return mEventBus;
        }
    }
    

    然后。来模拟他的注冊方法。

      public void register(Object obj){
    
            mObj = obj;
        }

    就是简单的对象传參。

    那么 如今在我们的Activity给他注冊一下:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            EventBusLite.getDefault().register(this);
        }
    }

    此时。就注冊成功了。


    然后来模拟他的Post方法。也就是发送消息方法。
    事实上post方法是回调了MainActivity的onEvent()方法。模拟例如以下:

    public void post(String str){
            try {
            //通过反射获取到这个类
                Class clazz = mObj.getClass();
                //获取到类的onEvent方法
                Method method = clazz.getMethod("onEvent",String.class);
                //运行这个实例的方法
                method.invoke(mObj,str);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    此时我们的post工作已经完毕。接下来仅仅需要写一个onEvent()方法就可以:

    public void onEvent(String str){
            Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
        }

    在MainActivity增加一个button。监听里面发送消息:

       @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            EventBusLite.getDefault().register(this);
            mButton = (Button) findViewById(R.id.btn);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    EventBusLite.getDefault().post("hi");
                }
            });
        }
    

    运行效果例如以下:
    这里写图片描写叙述

    哈哈哈哈,猜想实践完毕。

    如今,仅仅实现了postEvent模式:
    在当前的线程运行。
    那么其它onMainThread() onBackgroundThread()怎么实现呢?这里猜想为检查线程,然后使用handler。

    验证猜想

    接下来就是read the fxxking source code 的过程去验证我们的猜想。

    首先看看注冊的方法,因为我的水平也不高。。也看不非常懂。

    。所以这里就捡重点来看:

    register调用了双參的

      public void register(Object subscriber) {
            register(subscriber, false, 0);
        }

    继续往下找。。

     private synchronized void register(Object subscriber, boolean sticky, int priority) {
            List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod, sticky, priority);
            }
        }

    看到一个list 用来遍历寻找他这个类的方法。。

    这里已经能够确定了是通过反射调用他的方法。
    寻找方法的函数。。

     List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
     //叽里呱啦一大堆。。。。。
    
    
     while (clazz != null) {
                String name = clazz.getName();
                if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                    //这里假设以这些包名开头,就会break。否则会减少性能
                    break;
                }
         //叽里呱啦一大堆....
    
    //然后是裁剪字符串,ON_EVENT_METHOD_NAME的常量值为"onEvent"
                                String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
        //依据后面的函数名来获取调用模式
                                ThreadMode threadMode;
                                if (modifierString.length() == 0) {
                                    threadMode = ThreadMode.PostThread;
                                } else if (modifierString.equals("MainThread")) {
                                    threadMode = ThreadMode.MainThread;
                                } else if (modifierString.equals("BackgroundThread")) {
                                    threadMode = ThreadMode.BackgroundThread;
                                } else if (modifierString.equals("Async")) {
                                    threadMode = ThreadMode.Async;
                                } else {
                                    if (skipMethodVerificationForClasses.containsKey(clazz)) {
                                        continue;
                                    } else {
                                        throw new EventBusException("Illegal onEvent method, check for typos: " + method);
                                    }
                                }
     }

    接下来来看post是怎么实现的

      public void post(Object event) {
            PostingThreadState postingState = currentPostingThreadState.get();
            List<Object> eventQueue = postingState.eventQueue;
            eventQueue.add(event);
    
            if (!postingState.isPosting) {
                postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                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;
                }
            }
        }

    叽里呱啦一大堆,好烦啊。。然后点点点 看到了这种方法

    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);
            }
        }

    当中非常重要一句就是

    subscription.subscriberMethod.method.invoke(subscription.subscriber, event);

    他实际上就是在调用我们订阅者的函数啦。这里返回来去调用我们注冊的订阅者的方法。也就是通知到啦~~

    最后我们再来看看unregister 注销的方法

    public synchronized void unregister(Object subscriber) {
            List<Class<?

    >> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { unubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }

    非常easy的。

    仅仅是做了个remove操作。。

    最后

    呐。这里 因温特巴斯猜想 就结束了,基本上是依照预期来做的。

    这里学习一个未知的东西顺序是这样

    1. 学会用
    2. 猜想他的原理
    3. 模仿
    4. 看源代码验证猜想
    5. 有不一样的地方,去学习理解

    因为水平有限。有错误请及时评论指出。蟹蟹!

    啊哈哈哈,感谢。 假设你喜欢我的文章,求评论。请点击关注我。我们一同进步。

    本demo地址:点击打开链接

    參考文章:http://blog.csdn.net/lmj623565791/article/details/40920453

  • 相关阅读:
    iOS开发之Socket
    IOS开发之Bug--使用KVC的易错情况
    IOS开发之功能模块--给任意的UIView添加点击事件
    IOS开发之开发者账号遇到的bug
    iOS开发--关于TableViewCell的可视化设置细节
    学习Coding-iOS开源项目日志(四)
    Learn how to Use UIPageViewController in iOS
    关于Storyboard的使用
    学习Coding-iOS开源项目日志(三)
    学习Coding-iOS开源项目日志(二)
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7056116.html
Copyright © 2020-2023  润新知