EventBus猜想 ----手把手带你自己实现一个EventBus
本文是什么
本文是一篇怀着推測角度学习一个未知东西(EventBus)的文章。
- 先推測EventBus是怎样实现的。
- 依据推測去模仿他的实现。
- 查看源代码。验证猜想。
更深入的去理解他。
转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50628416
关于EventBus前面已经介绍了他的使用方法。
依据使用流程猜想
使用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操作。。
最后
呐。这里 因温特巴斯猜想 就结束了,基本上是依照预期来做的。
这里学习一个未知的东西顺序是这样
- 学会用
- 猜想他的原理
- 模仿
- 看源代码验证猜想
- 有不一样的地方,去学习理解
因为水平有限。有错误请及时评论指出。蟹蟹!
啊哈哈哈,感谢。 假设你喜欢我的文章,求评论。请点击关注我。我们一同进步。
本demo地址:点击打开链接
參考文章:http://blog.csdn.net/lmj623565791/article/details/40920453
EventBus猜想 ----手把手带你自己实现一个EventBus的更多相关文章
- 手把手带你做一个超炫酷loading成功动画view Android自定义view
写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...
- [.Net] 手把手带你将自己打造的类库丢到 NuGet 上
手把手带你将自己打造的类库丢到 NuGet 上 序 我们习惯了对项目右键点击“引用”,选择“管理NuGet 程序包”来下载第三方的类库,可曾想过有一天将自己的打造的类库放到 NuGet 上,让第三者下 ...
- Android EventBus源代码解析 带你深入理解EventBus
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...
- Android性能优化:手把手带你全面实现内存优化
前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录 1. 定义 优化处理 应用程序的内存使用.空间占用 2. 作用 避免因不正确使用内 ...
- Android:手把手带你深入剖析 Retrofit 2.0 源码
前言 在Andrroid开发中,网络请求十分常用 而在Android网络请求库中,Retrofit是当下最热的一个网络请求库 今天,我将手把手带你深入剖析Retrofit v2.0的源码,希望你们会喜 ...
- [转帖]从零开始入门 K8s | 手把手带你理解 etcd
从零开始入门 K8s | 手把手带你理解 etcd https://zhuanlan.zhihu.com/p/96721097 导读:etcd 是用于共享配置和服务发现的分布式.一致性的 KV 存储系 ...
- 手把手带你阅读Mybatis源码(三)缓存篇
前言 大家好,这一篇文章是MyBatis系列的最后一篇文章,前面两篇文章:手把手带你阅读Mybatis源码(一)构造篇 和 手把手带你阅读Mybatis源码(二)执行篇,主要说明了MyBatis是如何 ...
- GitHub 热点速览 Vol.26:手把手带你做数据库
作者:HelloGitHub-小鱼干 摘要:手把手带你学知识,应该是学习新知识最友好的姿势了.toyDB 虽然作为一个"玩具"项目不能应用在实际开发中,但通过它你可以了解到如何制作 ...
- 手把手带你体验鸿蒙 harmonyOS
wNlRGd.png 前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 image.png 一.为什么要尝鲜 harmonyos? wNlfx ...
随机推荐
- 【收藏】Web前端开发第三方插件大全
收集整理了一些Web前端开发比较成熟的第三方插件,分享给大家. ******************************************************************** ...
- Git(3)----Eclipse上Git插件使用技巧
转载:http://blog.csdn.net/qq_33066205/article/details/56675704 一_安装EGIT插件 http://download.eclipse.org/ ...
- 【分享】纯jQuery实现星巴克官网导航栏效果
前言 大冬天的没得玩,只能和代码玩. 所以就无聊研究了一下星巴克官网,在我看来应该是基本还原吧~ 请各位大神指教! 官网效果图 要写的就是最上方的会闪现的白色条条 效果分析 1.在滚动条往下拉到一定距 ...
- C语言系列之printf和%12d的用法(三)
看C语言程序的时候,往往会遇到printf函数输出,在此,我想总结一下printf的一般用法以及%12d是什么意思 printf函数的一般格式为 printf(格式控制,输出列表): 例如: prin ...
- Zabbix服务网页报错汇总
第1章 Zabbix简介及组成 1.1 zabbix简介 zabbix是一个基于web界面,提供分布式系统监视以及网络监视功能的企业级的开源解决方案.它可以监视各种网络参数,保证服务器自动的安全运营, ...
- osap一站式分析模型
运营系统分析平台技术设计: 项目定义于运营系统关键指标的数据分析 关键代码描述: HiveWriter 主要用于写hive表抽象,包括加分区,写hive表,写success文件: import org ...
- get和post请求及函数调用模式
1.get和post请求的应用场景? get: 1.get请求获取(查询)数据 2.请求url长度比较短 3.可以被缓存 4.请求url可以作为浏览器书签 5.可以被保存在浏览器记录中 6.请求参数在 ...
- webpack 3.X学习之Babel配置
Babel是什么 Babel是一个编译JavaScript的平台,它的强大之处表现在可以通过编译帮你达到: 使用下一代的javascript(ES6,ES7,--)代码,即使当前浏览器没有完成支持: ...
- 浅谈快速开发框架的分层(WinForm)
对于B/S都是MVC好不好 不多说了,反正大家都这么用 这里简单说下C/S 首先常用的几种: 模仿B/S的MVC 也有人称之为 MVP 还有MVVM这种真心觉得够够的了,当然也有其优势所在,这里不讨 ...
- MyBatis物理分页的代码实现
一.分页 MyBatis有两种分页方法:内存分页,也就是假分页,本质是查出所有的数据然后根据游标的方式,截取需要的记录,如果数据量大,执行效率低,可能造成内存溢出.物理分页,就是数据库本身提供了分页方 ...