本文是什么

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

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

    更深入的去理解他。

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

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

退出App新的优雅方式

依据使用流程猜想

使用EventBus的流程例如以下:

1. 注冊EventBus

  1. EventBus.getDefault().register(this);

2 . 发送一条消息

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

3.处理这条消息

  1. onEventMainThread()

原理猜想

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

猜想实现

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

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

  1. public class EventBusLite {
  2. private static EventBusLite mEventBus;
  3. private EventBusLite(){
  4. }
  5. public static EventBusLite getDefault(){
  6. if(mEventBus == null){
  7. mEventBus = new EventBusLite();
  8. }
  9. return mEventBus;
  10. }
  11. }

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

  1. public void register(Object obj){
  2. mObj = obj;
  3. }

就是简单的对象传參。

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

  1. public class MainActivity extends AppCompatActivity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. EventBusLite.getDefault().register(this);
  7. }
  8. }

此时。就注冊成功了。

然后来模拟他的Post方法。也就是发送消息方法。

事实上post方法是回调了MainActivity的onEvent()方法。模拟例如以下:

  1. public void post(String str){
  2. try {
  3. //通过反射获取到这个类
  4. Class clazz = mObj.getClass();
  5. //获取到类的onEvent方法
  6. Method method = clazz.getMethod("onEvent",String.class);
  7. //运行这个实例的方法
  8. method.invoke(mObj,str);
  9. } catch (ClassNotFoundException e) {
  10. e.printStackTrace();
  11. } catch (NoSuchMethodException e) {
  12. e.printStackTrace();
  13. } catch (InvocationTargetException e) {
  14. e.printStackTrace();
  15. } catch (IllegalAccessException e) {
  16. e.printStackTrace();
  17. }
  18. }

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

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

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

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.activity_main);
  5. EventBusLite.getDefault().register(this);
  6. mButton = (Button) findViewById(R.id.btn);
  7. mButton.setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View v) {
  10. EventBusLite.getDefault().post("hi");
  11. }
  12. });
  13. }

运行效果例如以下:

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

如今,仅仅实现了postEvent模式:

在当前的线程运行。

那么其它onMainThread() onBackgroundThread()怎么实现呢?这里猜想为检查线程,然后使用handler。

验证猜想

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

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

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

register调用了双參的

  1. public void register(Object subscriber) {
  2. register(subscriber, false, 0);
  3. }

继续往下找。。

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

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

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

寻找方法的函数。。

  1. List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
  2. //叽里呱啦一大堆。。。。。
  3. while (clazz != null) {
  4. String name = clazz.getName();
  5. if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
  6. //这里假设以这些包名开头,就会break。否则会减少性能
  7. break;
  8. }
  9. //叽里呱啦一大堆....
  10. //然后是裁剪字符串,ON_EVENT_METHOD_NAME的常量值为"onEvent"
  11. String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
  12. //依据后面的函数名来获取调用模式
  13. ThreadMode threadMode;
  14. if (modifierString.length() == 0) {
  15. threadMode = ThreadMode.PostThread;
  16. } else if (modifierString.equals("MainThread")) {
  17. threadMode = ThreadMode.MainThread;
  18. } else if (modifierString.equals("BackgroundThread")) {
  19. threadMode = ThreadMode.BackgroundThread;
  20. } else if (modifierString.equals("Async")) {
  21. threadMode = ThreadMode.Async;
  22. } else {
  23. if (skipMethodVerificationForClasses.containsKey(clazz)) {
  24. continue;
  25. } else {
  26. throw new EventBusException("Illegal onEvent method, check for typos: " + method);
  27. }
  28. }
  29. }

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

  1. public void post(Object event) {
  2. PostingThreadState postingState = currentPostingThreadState.get();
  3. List<Object> eventQueue = postingState.eventQueue;
  4. eventQueue.add(event);
  5. if (!postingState.isPosting) {
  6. postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
  7. postingState.isPosting = true;
  8. if (postingState.canceled) {
  9. throw new EventBusException("Internal error. Abort state was not reset");
  10. }
  11. try {
  12. while (!eventQueue.isEmpty()) {
  13. postSingleEvent(eventQueue.remove(0), postingState);
  14. }
  15. } finally {
  16. postingState.isPosting = false;
  17. postingState.isMainThread = false;
  18. }
  19. }
  20. }

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

  1. void invokeSubscriber(Subscription subscription, Object event) {
  2. try {
  3. subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
  4. } catch (InvocationTargetException e) {
  5. handleSubscriberException(subscription, event, e.getCause());
  6. } catch (IllegalAccessException e) {
  7. throw new IllegalStateException("Unexpected exception", e);
  8. }
  9. }

当中非常重要一句就是

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

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

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

  1. public synchronized void unregister(Object subscriber) {
  2. List<Class<?
  3. >> subscribedTypes = typesBySubscriber.get(subscriber);
  4. if (subscribedTypes != null) {
  5. for (Class<?> eventType : subscribedTypes) {
  6. unubscribeByEventType(subscriber, eventType);
  7. }
  8. typesBySubscriber.remove(subscriber);
  9. } else {
  10. Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
  11. }
  12. }

非常easy的。

仅仅是做了个remove操作。。

最后

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

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

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

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

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

本demo地址:点击打开链接

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

EventBus猜想 ----手把手带你自己实现一个EventBus的更多相关文章

  1. 手把手带你做一个超炫酷loading成功动画view Android自定义view

    写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...

  2. [.Net] 手把手带你将自己打造的类库丢到 NuGet 上

    手把手带你将自己打造的类库丢到 NuGet 上 序 我们习惯了对项目右键点击“引用”,选择“管理NuGet 程序包”来下载第三方的类库,可曾想过有一天将自己的打造的类库放到 NuGet 上,让第三者下 ...

  3. Android EventBus源代码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  4. Android性能优化:手把手带你全面实现内存优化

      前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录   1. 定义 优化处理 应用程序的内存使用.空间占用 2. 作用 避免因不正确使用内 ...

  5. Android:手把手带你深入剖析 Retrofit 2.0 源码

    前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将手把手带你深入剖析Retrofit v2.0的源码,希望你们会喜 ...

  6. [转帖]从零开始入门 K8s | 手把手带你理解 etcd

    从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...

  7. 手把手带你阅读Mybatis源码(三)缓存篇

    前言 大家好,这一篇文章是MyBatis系列的最后一篇文章,前面两篇文章:手把手带你阅读Mybatis源码(一)构造篇 和 手把手带你阅读Mybatis源码(二)执行篇,主要说明了MyBatis是如何 ...

  8. GitHub 热点速览 Vol.26:手把手带你做数据库

    作者:HelloGitHub-小鱼干 摘要:手把手带你学知识,应该是学习新知识最友好的姿势了.toyDB 虽然作为一个"玩具"项目不能应用在实际开发中,但通过它你可以了解到如何制作 ...

  9. 手把手带你体验鸿蒙 harmonyOS

    wNlRGd.png 前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 image.png 一.为什么要尝鲜 harmonyos? wNlfx ...

随机推荐

  1. MSSQL 备份数据库还原

    -- 完整还原RESTORE DATABASE XXXX FROM DISK = 'd:\XXXX.bak' WITH MOVE 'XXXX' TO 'D:\MSSQL\Data\XXXX.mdf', ...

  2. phpstudy APACHE支持.htaccess以及 No input file specified解决方案

    APACHE支持.htaccess以及 No input file specified解决方案 你的Apache安装文件夹conf里找到httpd.conf文件 索LoadModule rewrite ...

  3. SpringMVC接收复杂对象

    SpringMVC接收复杂对象 转载请注明地址:http://www.cnblogs.com/funnyzpc/p/7642977.html 本节内容暂放一边,我先扯点儿,心情好了,代码顺风顺水哈~ ...

  4. 深入探讨List<>中的一个姿势。

    List<>是c#中很常见的一种集合形式,近期在阅读c#源码时,发现了一个很有意思的定义: [DebuggerTypeProxy(typeof(Mscorlib_CollectionDeb ...

  5. pycharm安装和首次使用

    PyCharm 是由 JetBrains 打造的一款 Python IDE,支持 macOS. Windows. Linux 系统. PyCharm 功能 : 调试.语法高亮.Project管理.代码 ...

  6. python 有关datetime时间日期 以及时间戳转换

    直接上代码 其中有注释 #coding=utf-8 import time import datetime def yes_time(): #获取当前时间 now_time = datetime.da ...

  7. 线性代数之行列式的C#研究实现

    最近学习机器学习 才发现以前数学没有学好 开始从线性代数开始学起 读完行列式一章写了些C#的代码学习一下. 直接上C#代码: using System; using System.Collection ...

  8. 32.Linux-2440下的DMA驱动(详解)

    DMA(Direct Memory Access) 即直接存储器访问, DMA 传输方式无需 CPU 直接控制传输,通过硬件为 RAM .I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大 ...

  9. 一步一步搞懂支持向量机——从牧场物语到SVM(上)

    之前在数据挖掘课程上写了篇关于SVM的"科普文",尽量通俗地介绍了SVM的原理和对各公式的理解.最近给正在初学机器学习的小白室友看了一遍,他觉得"很好,看得很舒服&quo ...

  10. 深入理解Java内置锁和显式锁

    synchronized and Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两 ...