Android 开源项目EventBus详解
2015-12-27 18:28
525 查看
使用
//MainActivity public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); EventBus.getDefault().register(this); //注册MainActivity到eventbus } @OnClick(R.id.but) void onClick() { startActivityForResult(new Intent(this, AnoActivity.class), TEST_REUQUEST_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { formatCurrentTime("onActivityResult"); super.onActivityResult(requestCode, resultCode, data); if (requestCode == TEST_REUQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { if (data == null) { return; } QDLog.d("onActivityResult text:" + data.getStringExtra("textview")); } } } public void onEventMainThread(Object object) { QDLog.d("onEventMainThread object:" + object.toString()); } public void onEventMainThread(String text) { QDLog.d("onEventMainThread text:" + text); } public void onEvent(String text) { QDLog.d("onEvent text:" + text); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); //别忘记去注册,否则会引起activity释放不了,最后导致OOM } } //MainActivity跳转到AnoActivity @OnClick(R.id.but) void OnClick() { EventBus.getDefault().post("event buts for test"); Intent intent = new Intent(); intent.putExtra("textview", "onActivityResult for test"); setResult(Activity.RESULT_OK, intent); //setResult必须放在finish之前,否则resultCode设置无效的 finish(); }
以上使用了两种通信方式,1. intent 2. eventbus
不使用eventbus,我们一般使用intent作为activity之间互相通信
最后结果:
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEvent text:event buts for test
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEventMainThread text:event buts for test
12-27 04:55:12.206 19141-19141/demo.lbb.mytest D/LiaBin: onEventMainThread object:event buts for test
12-27 04:55:12.217 19141-19141/demo.lbb.mytest D/LiaBin: onActivityResult text:onActivityResult for test
注意:虽然post的是String类型,但是String是Object的间接之类,同时库中eventInheritance默认为true,所以
onEventMainThread(Object object)也可执行到,见以下分析
此时注意到
eventbus方式只要调用post方法,那么MainActivity的onEvent..方法就能执行到;
intent方式只有把anoactivity销毁finish了才会回调onActivityResult方法。
所以有这么个需求,anoactivity点击同时停留在本界面,然后mainactivity立刻执行某项任务,那么eventbus无疑是很合适的
源码分析
先上原理图:eventbus实际上实现的就是观察者模式的功能,只是eventbus内部通过反射来实现的而已
register方法
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<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());通过反射的原理,把
当前类和父类的所有onEvent..的方法添加到list,同时返回该list,此时也说明,比如MainActivity继承了BaseActivity,那么onEventMainThread(String text)只有一个地方会生效,另一个会覆盖掉。这里有个优化
String name = clazz.getName(); if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { // Skip system classes, this just degrades performance break; }
如果是系统包中的类,就中断while了
SubscriberMethod构造如下:
final Method method; //.MainActivity.onEventMainThread(java.lang.String) final ThreadMode threadMode; //MainThread final Class<?> eventType; //class java.lang.String public enum ThreadMode { PostThread,MainThread,BackgroundThread,Async //四种模式 }
Subscription构造如下:
final Object subscriber; final SubscriberMethod subscriberMethod; final int priority;
subscribe方法源码就不贴了,主要就是对
subscriptionsByEventType和
typesBySubscriber全局变量进行赋值
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; //订阅方法作为key,所有的订阅对象作为value 此时说明了每种类型,都有几个订阅对象订阅了 private final Map<Object, List<Class<?>>> typesBySubscriber; //订阅对象作为key,订阅对象中所有的订阅方法作为value 此时说明订阅对象声明了几个订阅方法 //MainActivity中有以下三方方法 public void onEventMainThread(Object object); public void onEventMainThread(String text); public void onEvent(String text);
所以最后的结果为:
subscriptionsByEventTypesize为2,第一个key为Object,value长度为1,第二个key是String,CopyOnWriteArrayList>长度是2
typesBySubscribersize为1,key为当前订阅对象,List
post方法
post方法中使用到了currentPostingThreadState来根据线程的状态分别执行private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
ThreadLocal是不是很熟悉,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
handler机制中就看到了该类的使用,很方便。
post然后调用postSingleEvent方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; if (eventInheritance) { //默认为true //此时event实际类型为String,那么最后eventTypes长度为5,里面保存String以及String所有的父类以及实现的接口: //String/Serializable/Comparable/CharSequence/Object List<Class<?>> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); for (int h = 0; h < countTypes; h++) { //此时会循环5次 Class<?> clazz = eventTypes.get(h); subscriptionFound |= postSingleEventForEventType(event, postingState, clazz); } } else { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } .... } private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<Class<?>>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces());//拿到该class实现的所有接口 clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();//String,Object等发布类型为key,List
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); //subscriptionsByEventType取出订阅者 } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread); //掉用postToSubscription方法 aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; } private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case PostThread: invokeSubscriber(subscription, event); //在当前线程中调用订阅方法,所以最好不要使用该模式,而是使用以下三种模式 break; case MainThread: if (isMainThread) { //如果当前线程是main线程,直接调用订阅方法 invokeSubscriber(subscription, event); } else { //否则通过mainThreadPoster,内部通过handler,发送到main线程中执行订阅方法 mainThreadPoster.enqueue(subscription, event); } break; case BackgroundThread: if (isMainThread) { //如果当前线程是main线程,缓存线程池中新建一个线程执行订阅方法 backgroundPoster.enqueue(subscription, event); } else { //否则在当前线程中调用订阅方法 invokeSubscriber(subscription, event); } break; case Async: asyncPoster.enqueue(subscription, event); //缓存线程池中新建一个线程执行订阅方法 break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } } subscription.subscriberMethod.method.invoke(subscription.subscriber, event); //最后都是执行到了这里,反射方法执行
private final HandlerPoster mainThreadPoster; //继承自handler,内部持有main线程的loop private final BackgroundPoster backgroundPoster; //继承自runnable,执行放在线程池中运行 private final AsyncPoster asyncPoster; //继承自runnable,执行放在线程池中运行 private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool(); //默认使用缓存线程池来管理
总结一下:
每注册一个对象和方法,就放入map,之后post(Object)就去这个Map中查找匹配的类方法调用
可以看到此时不仅可以接收activity,service等组件的注册,其实可以接收任何类的注册
缺点
1. 这里使用到了build设计模式什么鬼,设计的有点差劲,,,EventBusBuilder完全就是个摆设,为了把eventInheritance置为false,只有修改库源码了,没有提供接口供修改
eventInheritance设为false,极大的提升了性能
任何项目引入开源项目一定要对开源项目后,进行修改,不能只照搬。
2. 自定义queue导致性能差
BackgroundPoster的run方法
private final PendingPostQueue queue; @Override public void run() { try { try { while (true) { PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { Log.w("Event", Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } }
PendingPostQueue是一个自定义的队列,方法内部使用synchronized关键子来防止多线程造成的同步问题,麻烦同时效率低下,为何不直接使用
BlockingQueue队列,参考Volley实现,BlockingQueue是java推荐的实现方式
3. 默认线程池的选择CachedThreadPool
默认线程池使用的是CachedThreadPool,虽然实时性好,但是频繁的创建线程,开销大
CachedThreadPool特性:excute了一个任务,就创建一个线程,不需要等待
我觉得使用newFixedThreadPool可能会更好些,虽然实时性可能不大好,会等待
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories