EventBus猜想 ----手把手带你自己实现一个EventBus
来源:互联网 发布:协同过滤推荐算法实例 编辑:程序博客网 时间:2024/06/10 18:06
本文是什么
本文是一篇怀着猜测角度学习一个未知东西(EventBus)的文章。
- 先猜测EventBus是如何实现的。
- 根据猜测去模仿他的实现。
- 查看源码,验证猜想。更深入的去理解他。
转载请注明出处: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操作。。
最后
呐,这里 因温特巴斯猜想 就结束了,基本上是按照预期来做的。这里学习一个未知的东西顺序是这样
- 学会用
- 猜想他的原理
- 模仿
- 看源码验证猜想
- 有不一样的地方,去学习理解
由于水平有限,有错误请及时评论指出,蟹蟹!
啊哈哈哈,感谢! 如果你喜欢我的文章,求评论,请点击关注我。我们一同进步。
本demo地址:点击打开链接
参考文章:http://blog.csdn.net/lmj623565791/article/details/40920453
- EventBus猜想 ----手把手带你自己实现一个EventBus
- EventBus猜想 ----手把手带你自己实现一个EventBus
- 教你自己实现一个事件总线EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- EventBus
- Eventbus
- EventBus
- C# PropertyInfo 将一个对象赋值到另一个相同名称的对象
- 过滤器(当前登录人的信息(session过期时)进行重新登录)
- 生成openfpyxl html格式帮助文档
- Linux:C/Socket多路复用select
- NSURLSession使用说明及后台工作流程分析
- EventBus猜想 ----手把手带你自己实现一个EventBus
- android 65535 多dex文件方案
- spring mvc+ mybaties+ehcache(maven工程),在mapper.xml中使用
- zookeeper应用场景练习(分布式锁)
- CLLocationCoordinate2D 初始化
- Angular的作用域Scope理解
- Redis 实例: 集群
- php中必须表单
- spring mvc+ mybaties+ehcache(maven工程),在service层中使用