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加入一个按钮,监听里面发送消息:

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

很简单的。。只是做了个remove操作。。

最后

呐,这里 因温特巴斯猜想 就结束了,基本上是按照预期来做的。这里学习一个未知的东西顺序是这样

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

由于水平有限,有错误请及时评论指出,蟹蟹!

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

本demo地址:点击打开链接

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

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值