EventBus源码分析
来源:互联网 发布:如何修改 淘宝会员名 编辑:程序博客网 时间:2024/06/16 16:46
EventBus是专门为Android设计的用于订阅,发布总线的库,用到这个库的app很多,因为它有很多的优点。比如,它可以简单android组件之间的通信;它可以避免了android四大组件复杂的生命周期处理;它可以让你的代码更为简洁。
一、基本用法:
1、导入依赖库
dependencies { compile 'org.greenrobot:eventbus:3.0.0'}
2、定义发送事件类型
public class MessageEvent { public String message; public MessageEvent(String message) { this.message = message; }}
或者
public class EventBean { public String type; //发送消息类型 public Object msg; //发送消息数据 public EventBean(String type, Object msg) { this.type = type; this.msg = msg; }}
3、在需要的地方地方订阅、发送事件、接收事件
public class MainActivity extends AppCompatActivity { private String TAG = getClass().getSimpleName(); ActivityMainBinding mainBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main); EventBus.getDefault().register(this); //订阅 mainBinding.bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //发送事件 EventBus.getDefault().post(new MessageEvent("事件一")); } }); mainBinding.bt2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //发送事件 EventBus.getDefault().post(new EventBean("事件二","123")); } }); } //接收事件 @Subscribe(threadMode = ThreadMode.MAIN,priority = 10,sticky = true) public void onMessageEvent(MessageEvent event) { mainBinding.tv.setText(event.message); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMainUiThread(EventBean event) { mainBinding.tv.setText(event.type); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); //取消订阅 }
说明:
@Subscribe可以在代码中就指定我们的EventBus使用什么ThreadMode,是否粘性事件,优先级。粘性事件:没有接收事件的函数就会一直等待,直到有函数处理。Object订阅时就会判断执行粘性事件EventBus的四种ThreadMode(线程模型) POSTING(默认):事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。 BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。 ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。
二、原理分析
@Subscribe:
@Documented@Retention(RetentionPolicy.RUNTIME) //运行时注解@Target({ElementType.METHOD}) //作用在方法上public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; //在什么线程处理 boolean sticky() default false; //是否是粘性事件() int priority() default 0; //事件优先级}
ThreadMode:
public enum ThreadMode { POSTING, MAIN, BACKGROUND, ASYNC}
先分析下EventBus的构造方法:
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
public EventBus() { this(DEFAULT_BUILDER); }
初始化各种信息:
EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; sendNoSubscriberEvent = builder.sendNoSubscriberEvent; throwSubscriberException = builder.throwSubscriberException; eventInheritance = builder.eventInheritance; executorService = builder.executorService; }
从订阅方法开发分析,它是使用的入口:
EventBus.getDefault().register(this);
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); //根据订阅者使用反射得到事件监听方法,订阅者里面可以有很多事件处理方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
subscriberMethodFinder使用反射的方式从订阅者subscriber及其父类中找到所有的SubscriberMethod,即上面使用实例中的
@Subscribe(threadMode = ThreadMode.MAIN,priority = 10,sticky = true) public void onMessageEvent(MessageEvent event) { mainBinding.tv.setText(event.message); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMainUiThread(EventBean event) { mainBinding.tv.setText(event.type); }
SubscriberMethod结构:
public class SubscriberMethod { final Method method; //事件方法名 final ThreadMode threadMode; //在什么线程处理 final Class<?> eventType; //事件处理函数里面的参数,发送什么、处理什么 final int priority; final boolean sticky;}
subscriberMethodFinder最后会调用如下方法生成SubscriberMethod
//订阅者、订阅者父类中去找@Subscribe方法 private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException("@Subscribe method " + methodName + "must have exactly 1 parameter but has " + parameterTypes.length); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
找到SubscriberMethod了,接下来把它们保存在相应的集合里面,如果是粘性事件就会立即处理:
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); if (subscriberMethod.sticky) { if (eventInheritance) { Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet(); for (Map.Entry<Class<?>, Object> entry : entries) { Class<?> candidateEventType = entry.getKey(); if (eventType.isAssignableFrom(candidateEventType)) { Object stickyEvent = entry.getValue(); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } } else { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
EventBus里面的几个集合说明:
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); //订阅者,订阅者和事件方法生成Subscription。一个订阅者里面可以有多个Subscription。post事件的时候,调用Subscription里面的SubscriberMethod保存的Method,通过反射执行该方法 private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; //订阅者,事件类型。根据我们的订阅对象找到EventType。取消订阅时使用 private final Map<Object, List<Class<?>>> typesBySubscriber; //订阅者,事件类型。缓存粘性事件 private final Map<Class<?>, Object> stickyEvents;
到这里register流程就完成了,接下来分析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; } } }
接下来,调用postSingleEvent()->postSingleEventForEventType(),最后在postToSubscription()中处理:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread){ switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { 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); } }
mainThreadPoster、backgroundPoster:如果发送事件的线程和处理事件的线程不在同一个线程就调用它们进行处理,最后它们也会调用下面方法处理事件:
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); //订阅者里面的@Subscriber注解的方法会被调用 } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
到此Post逻辑、事件处理流程已经完成,接下来还有取消订阅。
public synchronized void unregister(Object subscriber) { 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()); } }
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
从相应集合中删除register时保存的数据。
到此EventBus主要流程就清楚了。
参考资料:
源码
EventBus3.0 源码解析
EventBus3.0 源码解析
- EventBus 2.4 源码分析
- EventBus源码注释分析
- EventBus框架源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus 源码分析
- EventBus 源码分析
- EventBus的源码分析
- EventBus 3 源码分析
- EventBus 源码分析
- EventBus的源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus源码分析
- EventBus 3.0 源码分析
- EventBus 3.0 源码分析
- EventBus源码分析
- 【大数据部落】文本挖掘:LDA模型对公号文章主题分析
- 动态规划基础和分治法基础
- 异常
- 旋转数组的最小数字
- Chapter 2. Variables and Basic Types
- EventBus源码分析
- 51Nod
- SSH总结
- Vim常用命令
- 压缩与解压
- react-navigation使用技巧(进阶篇)
- python 读写 excel 笔记
- 【树状数组】学习树状数组
- Comparable