您的位置:首页 > 移动开发 > Android开发

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);


所以最后的结果为:

subscriptionsByEventType
size为2,第一个key为Object,value长度为1,第二个key是String,CopyOnWriteArrayList>长度是2

typesBySubscriber
size为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可能会更好些,虽然实时性可能不大好,会等待
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android eventbus