简读Eventbus3.0
简单了解一下eventbus的工作情况,学学大神的思想,那么在此篇文章之前呢,建议大家先要了解清楚何为注解和反射,如果没了解,可以先看看前一篇文章,有具体的介绍 Android 注解 (Annotation)
使用过eventbus的都知道,eventbus是一个Android事件发布/订阅轻量级框架, 它可以完美的在任何地方完成通信任务,那么不废话啦,按照 咱们在Android中的使用过程为思路展开一个了解吧
一、我们是在需要接受事件的地方(例如activity、fragment) 注册 eventbus事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
//注册eventbus事件
EventBus.getDefault().register(this);
}
好啦,如上代码,我们在activity的oncreate生命周期方法中注册了eventbus事件,那么来看一下 getDefault()、register()方法到底干了点什么
//第一部分,获取单例(懒汉式,"懒得创建自己")
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
//第二部分,注册给定的订阅服务器以接收事件。订阅者必须调用{unregister(Object)取消注册(对象)}
public void register(Object subscriber) {
//1.首先通过反射获取到当前类
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);//3
}
}
}
第一部分 EventBus.getDefault() 是一个懒汉式单例。
第二部分是注册,1.首先通过当前object.getclass()反射方法获取到当前 class对象; 2.然后通过 findSubscriberMethods 方法获取到一个当前class对象的所有方法,并放在一个list集合中,List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); 该行代码中就是就是维护了 一个 ConcurrentHashMap 对象 ; 3.接下来就是一个 synchronized 同步块,把该类和该类的多个方法进行配对订阅
二、发送提交和订阅消费
提交事件到总线: EventBus.getDefault().post(object);
//将给定事件提交到事件总线
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get(); //1
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {//2
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);//3
}
} finally { //最终把状态都还原了
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
//-------------------current Posting Thread State --------------------------
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
//------------------Posting Thread State------------------------
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>(); //消息集合
boolean isPosting; //是否有发送
boolean isMainThread; //是否是主线程
Subscription subscription; //订阅关系
Object event; //具体发送的事件体
boolean canceled; //是否取消了
}
1. PostingThreadState postingState = currentPostingThreadState.get() 该方法其实就是ThreadLocal对象(线程副本,为线程本身存储变量等信息),而PostingThreadState就是线程副本内所存储JavaBean对象 (在此可以看出,该bean对象并没有get set封装),从bean对象中获取到消息集合,并把当前post所要提交的消息保存在该集合中;
2. 使用 isposting 来判断是否发送过信息,然后进入下一步判断当前发送post方法执行的线程是否是主线程,设置发送状态,判断消息是否有效,while遍历
3. while在集合非空状态下,会不断遍历 postSingleEvent 方法,不断从集合中获取消息体和副本中数据进行处理,那么在往下查看有 postToSubscription(subscription, event, postingState.isMainThread) 这样的方法,它主要就是获取咱们标签中的value,根据不同的value 在不同的线程做不同的操作
//常用的四个标签
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING://当前线程执行
invokeSubscriber(subscription, event);
break;
case MAIN: //事件的消费会在UI线程。因此,不宜进行耗时操作,以免引起ANR
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND://背景线程,如果事件在UI线程产生,那么事件的消费会在单独的子线程中进行。否则,在同一个线程中消费。
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC://异步执行,不管是否在UI线程产生事件,都会在单独的子线程中消费事件
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
//---------------------反射中的 方法执行---------------------------
void invokeSubscriber(Subscription subscription, Object event) {
try {
//通过反射获取到要执行的方法 subscription.subscriber,该方法的参数就是 通过 post要提交的消息
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
三、注销
EventBus.getDefault().unregister(this);
//每个待消费事件的class都会对应一个list集合
private final Map<Object, List<Class<?>>> typesBySubscriber;
//取消注册
public synchronized void unregister(Object subscriber) {
//获取该activity或fragment对应的注解类
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
// 遍历所有的订阅方法 ,并取消
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
在使用的时候只是简单导入eventbus jar,我们调用的时候只要简单的注册和配置注解标签即可,极大提供了开发效率,这就是提供框架的好处;另外重要的一点,就是学习文中的“注册”与“注销”的精神,程序做到了有始有终,在开辟了内存,在内存中完成业务,然后在view组件结束生命周期的时候把所占的内存、操作都结束了 ;初次解读,有问题的地方要指出,互相提高吧