当前位置: 首页 > news >正文

平面设计图案/无锡优化网站排名

平面设计图案,无锡优化网站排名,山西大同网站建设哪家好,html5网页制作代码大全EventBus 3.1.1源码分析前言EventBus构造方法订阅者注册查找订阅者方法注册过程发送事件订阅者取消注册前言 EventBus 是一款在 Android 开发中经常使用的发布/订阅事件总线框架,将事件的接收者和发送者分开;简化了组件之间的通信,使用简单、…

EventBus 3.1.1源码分析

      • 前言
      • EventBus构造方法
      • 订阅者注册
        • 查找订阅者方法
        • 注册过程
      • 发送事件
      • 订阅者取消注册

前言

EventBus 是一款在 Android 开发中经常使用的发布/订阅事件总线框架,将事件的接收者和发送者分开;简化了组件之间的通信,使用简单、效率高、体积小!由于经常使用到,所以我们深入理解该框架的原理就很有必要了,下面我们就来分析一下EventBus原理。

EventBus构造方法

大家都知道当我们在使用EventBus时,首先会调用EventBus.getDefault()方法来获取EventBus的实例。那我们来看一下getDefault()方法,代码如下:

	/** Convenience singleton for apps using a process-wide EventBus instance. */public static EventBus getDefault() {if (defaultInstance == null) {synchronized (EventBus.class) {if (defaultInstance == null) {defaultInstance = new EventBus();}}}return defaultInstance;}

这是一个双重检查模式单例模式。
接下来是EventBus构造方法,代码如下:

	/*** Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a* central bus, consider {@link #getDefault()}.*/public EventBus() {this(DEFAULT_BUILDER);}EventBus(EventBusBuilder builder) {logger = builder.getLogger();subscriptionsByEventType = new HashMap<>();typesBySubscriber = new HashMap<>();stickyEvents = new ConcurrentHashMap<>();mainThreadSupport = builder.getMainThreadSupport();mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;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;}

这里DEFAULT_BUILDER是默认的EventBusBuilder:

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

这里调用了EventBus的另外一个构造方法,采用了建造者模式,通过构造EventBusBuilder来配置EventBus。

订阅者注册

获取到EventBus的实例以后就调用register(this)方法将订阅者注册到EventBus中,register()方法代码如下:

	public void register(Object subscriber) {Class<?> subscriberClass = subscriber.getClass();List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//得到一个SubscriberMethod的集合,就是传进来的订阅者的所有订阅方法synchronized (this) {for (SubscriberMethod subscriberMethod : subscriberMethods) {//遍历订阅者的订阅方法来完成订阅者的注册操作subscribe(subscriber, subscriberMethod);}}}

register方法做了两件事:一件事是查找订阅者的订阅方法,另一件事是订阅者的注册。
SubscriberMethod类主要用来保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是黏性事件等属性。

public class SubscriberMethod {final Method method;final ThreadMode threadMode;final Class<?> eventType;final int priority;final boolean sticky;/** Used for efficient comparison */String methodString;public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {this.method = method;this.threadMode = threadMode;this.eventType = eventType;this.priority = priority;this.sticky = sticky;}........其他方法........
}

查找订阅者方法

接下来看看findSubscriberMethods(subscriberClass)方法代码:

	List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//从缓存中查找是否有订阅方法的集合if (subscriberMethods != null) {//如果找到就return return subscriberMethods;}//如果缓存中没有,则根据 ignoreGeneratedIndex属性的值来选择采用何种方法来查找订阅方法的集合//ignoreGeneratedIndex 的默认值是 false,可以通过EventBusBuilder来设置它的值if (ignoreGeneratedIndex) {subscriberMethods = findUsingReflection(subscriberClass);} else {subscriberMethods = findUsingInfo(subscriberClass);}if (subscriberMethods.isEmpty()) {throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");} else {METHOD_CACHE.put(subscriberClass, subscriberMethods);//找到订阅方法的集合后,放入缓存return subscriberMethods;}}

ignoreGeneratedIndex 属性表示是否忽略注解器生成的 MyEventBusIndex,具体可以看官网:http://greenrobot.org/eventbus/documentation/subscriber-index/

项目中经常通过EventBus单例模式来获取默认的EventBus对象,也就是ignoreGeneratedIndex为false的情况,这种情况调用了findUsingInfo(subscriberClass)方法,代码如下:

	private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {FindState findState = prepareFindState();findState.initForSubscriber(subscriberClass);while (findState.clazz != null) {findState.subscriberInfo = getSubscriberInfo(findState);//获取订阅者信息if (findState.subscriberInfo != null) {//如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取到subscriberInfoSubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//得到订阅方法相关的信息for (SubscriberMethod subscriberMethod : array) {if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {findState.subscriberMethods.add(subscriberMethod);}}} else {//没有配置MyEventBusIndexfindUsingReflectionInSingleClass(findState);//将订阅方法保存到findState中}findState.moveToSuperclass();}return getMethodsAndRelease(findState);//对findState做回收处理并返回订阅方法的List集合}

在开始查找订阅方法的时候并没有忽略注解器为我们生成的索引 MyEventBusIndex。

如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取subscriberInfo(这个参考上面ignoreGeneratedIndex为true的情况所调用的方法findUsingReflection(subscriberClass));
没有配置MyEventBusIndex便会执行findUsingReflectionInSingleClass(findState)方法;

最后再通过getMethodsAndRelease(findState)方法对findState做回收处理并返回订阅方法的List集合,这里贴一下getMethodsAndRelease(findState)方法代码:

	private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);findState.recycle();synchronized (FIND_STATE_POOL) {for (int i = 0; i < POOL_SIZE; i++) {if (FIND_STATE_POOL[i] == null) {FIND_STATE_POOL[i] = findState;break;}}}return subscriberMethods;}

默认情况下是没有配置MyEventBusIndex的,所以就会调用findUsingReflectionInSingleClass(findState)方法,代码如下:

	private void findUsingReflectionInSingleClass(FindState findState) {Method[] methods;try {// This is faster than getMethods, especially when subscribers are fat classes like Activitiesmethods = findState.clazz.getDeclaredMethods();//通过反射来获取订阅者中的方法} catch (Throwable th) {// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149methods = findState.clazz.getMethods();findState.skipSuperClasses = true;}for (Method method : methods) {int modifiers = method.getModifiers();//根据方法的类型、参数和注解来找到订阅方法。找到订阅方法后将订阅方法的相关信息保存到findState中。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");}}}

注册过程

上面register方法里面遍历SubscriberMethod对所有的订阅方法进行注册,调用了subscribe(subscriber, subscriberMethod)方法,代码如下:

	// Must be called in synchronized blockprivate void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {Class<?> eventType = subscriberMethod.eventType;//根据subscriber(订阅者)和subscriberMethod(订阅方法)创建一个Subscription(订阅对象)Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//根据eventType(事件类型)获取Subscriptions(订阅对象集合)CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {//如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType中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);//通过subscriber获取subscribedEvents事件类型集合if (subscribedEvents == null) {subscribedEvents = new ArrayList<>();//为空重新创建对象typesBySubscriber.put(subscriber, subscribedEvents);//根据subscriber将subscribedEvents存储在typesBySubscriber集合中}subscribedEvents.add(eventType);//将eventType添加到subscribedEvents中if (subscriberMethod.sticky) {if (eventInheritance) {//黏性事件处理// Existing sticky events of all subclasses of eventType have to be considered.// Note: Iterating over all events may be inefficient with lots of sticky events,// thus data structure should be changed to allow a more efficient lookup// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).//从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者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);}}}

subscribe()方法主要就是做了两件事:
1、将Subscriptions根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中;
2、对黏性事件的处理。

发送事件

我们通过post方法来对事件进行发送,所以我们看一下post()方法源码:

	/** Posts the given event to the event bus. */public void post(Object event) {PostingThreadState postingState = currentPostingThreadState.get();List<Object> eventQueue = postingState.eventQueue;//取出事件队列eventQueue.add(event);//将当前事件插入到事件队列if (!postingState.isPosting) {postingState.isMainThread = isMainThread();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;}}}

PostingThreadState 保存事件队列和线程状态信息,currentPostingThreadState.get()方法获取到PostingThreadState 对象,currentPostingThreadState代码如下:

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {@Overrideprotected PostingThreadState initialValue() {return new PostingThreadState();}};

上面从PostingThreadState对象中取出事件队列,然后再将当前的事件插入事件队列;通过postSingleEvent(eventQueue.remove(0), postingState)方法处理和移除该事件,代码如下:

	private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {Class<?> eventClass = event.getClass();boolean subscriptionFound = false;//eventInheritance 表示是否向上查找事件的父类,它的默认值为 true,可以通过在EventBusBuilder中进行配置if (eventInheritance) {List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//找到所有的父类事件并存在List中int countTypes = eventTypes.size();for (int h = 0; h < countTypes; h++) {Class<?> clazz = eventTypes.get(h);subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);//事件挨个处理}} else {subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);}if (!subscriptionFound) {//找不到事件的处理方式if (logNoSubscriberMessages) {logger.log(Level.FINE, "No subscribers registered for event " + eventClass);}if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&eventClass != SubscriberExceptionEvent.class) {post(new NoSubscriberEvent(this, event));}}}

接下来我们看看postSingleEventForEventType()方法的代码:

	private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {CopyOnWriteArrayList<Subscription> subscriptions;synchronized (this) {subscriptions = subscriptionsByEventType.get(eventClass);//同步取出该事件对应的Subscriptions订阅对象集合}if (subscriptions != null && !subscriptions.isEmpty()) {//遍历Subscriptions,将事件 event 和对应的 Subscription(订阅对象)传递给postingStatefor (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;}

接下来看postToSubscription(subscription, event, postingState.isMainThread)方法代码:

	private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {//取出订阅方法的threadMode,根据threadMode来分别处理switch (subscription.subscriberMethod.threadMode) {// 默认的线程模式,在那个线程发送事件就在那个线程处理事件case POSTING:invokeSubscriber(subscription, event);break;// 在主线程处理事件case MAIN:if (isMainThread) {invokeSubscriber(subscription, event);// 如果在主线程发送事件,则直接在主线程通过反射处理事件} else {// 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件mainThreadPoster.enqueue(subscription, event);}break;// 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。case MAIN_ORDERED:if (mainThreadPoster != null) {mainThreadPoster.enqueue(subscription, event);} else {// temporary: technically not correct as poster not decoupled from subscriberinvokeSubscriber(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);}}

根据threadMode来分别处理。如果threadMode是MAIN,提交事件的线程是主线程,则通过反射直接运行订阅的方法;若其不是主线程,则需要mainThreadPoster 将我们的订阅事件添加到主线程队列中。mainThreadPoster是HandlerPoster类的一个实例,继承自Handler,通过Handler将订阅方法切换到主线程执行,看下该类的主要实现,代码如下:

public class HandlerPoster extends Handler implements Poster {private final PendingPostQueue queue;private final int maxMillisInsideHandleMessage;private final EventBus eventBus;private boolean handlerActive;protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {super(looper);this.eventBus = eventBus;this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;queue = new PendingPostQueue();}public void enqueue(Subscription subscription, Object event) {// 用subscription和event封装一个PendingPost对象PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);synchronized (this) {queue.enqueue(pendingPost);// 加入队列if (!handlerActive) {handlerActive = true;// 发送开始处理事件的消息,handleMessage()方法将被执行,完成从子线程到主线程的切换if (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}}}}@Overridepublic void handleMessage(Message msg) {boolean rescheduled = false;try {long started = SystemClock.uptimeMillis();while (true) {// 死循环遍历队列PendingPost pendingPost = queue.poll();if (pendingPost == null) {synchronized (this) {// Check again, this time in synchronizedpendingPost = queue.poll();// 出队列if (pendingPost == null) {handlerActive = false;return;}}}eventBus.invokeSubscriber(pendingPost);// 进一步处理pendingPostlong timeInMethod = SystemClock.uptimeMillis() - started;if (timeInMethod >= maxMillisInsideHandleMessage) {if (!sendMessage(obtainMessage())) {throw new EventBusException("Could not send handler message");}rescheduled = true;return;}}} finally {handlerActive = rescheduled;}}
}

订阅者取消注册

取消注册就调用unregister()方法,代码如下所示:

	/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object subscriber) {List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);//通过subscriber找到subscribedTypes事件类型集合if (subscribedTypes != null) {for (Class<?> eventType : subscribedTypes) {unsubscribeByEventType(subscriber, eventType);//遍历 subscribedTypes}typesBySubscriber.remove(subscriber);//将subscriber对应的eventType从 typesBySubscriber中移除} else {logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());}}

接下来看unsubscribeByEventType(subscriber, eventType)方法,代码如下:

	/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {//通过eventType来得到对应的Subscriptions订阅对象集合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);//如果Subscription(订阅对象)的subscriber(订阅者)属性等于传进来的subscriber,则从Subscriptions中移除该Subscriptionif (subscription.subscriber == subscriber) {subscription.active = false;subscriptions.remove(i);//移除该Subscriptioni--;size--;}}}}

以上就是EventBus的源码分析。

http://www.lbrq.cn/news/1336393.html

相关文章:

  • 如何将自己做的网站挂到服务器上/深圳百度推广代理商
  • 无锡网站搜索优化/北京seo推广服务
  • 天津网页制作网页报价/优化方案官方网站
  • 从零精通网站建设/公司软文怎么写
  • 古典网站织梦模板/网站seo查询
  • 电脑报网站建设/南宁优化网站收费
  • 开奖网站怎么做/百度扫一扫识别图片
  • 免费网站建设咨询/最近新闻报道
  • phpcms主题移植wordpress/seo短视频网页入口引流
  • 郑州第一附属医院不孕不育科/seo关键词快速提升软件官网
  • 产品推广方案推广思路和方法/seo流量增长策略
  • 建设集团网站 技术支持中企动力/广州seo诊断
  • 做IT的会做网站吗/搜索引擎营销的英文简称
  • 低代码平台开发/长沙市seo百度关键词
  • 深圳做网上商城网站/怎样开自己的网站
  • 岳阳做公司网站/免费打广告网站
  • 域名解析过程/网站关键词如何优化上首页
  • vps设置网站访问用户权限/百度推广登录官网
  • 手机做炫光图头像的网站/企业网络搭建方案
  • php网站分类目录源码/搜索引擎营销的内容和层次有哪些
  • 淘宝网页美工设计/seo专员是什么职业
  • 网站编程源码免费/2022拉新推广赚钱的app
  • 陕西网站建设咨询/seo黑帽教程视频
  • 营销型网站建设主要教学内容/小程序平台
  • 企业网站排行榜/一站式软文发布推广平台
  • 做英文网站公司/手机网站免费客服系统
  • 影视广告宣传片制作公司/seo搜索排名
  • 网站建设都用哪个好/网络销售的工作内容
  • 基于java开发网站开发/5188关键词平台
  • 北京米兰广告设计有限公司/网站推广与优化平台
  • 一起来聊聊GPT-5
  • 面试经典150题[001]:合并两个有序数组(LeetCode 88)
  • 【牛客刷题】REAL809 转化
  • C#高级语法_泛型
  • Selenium动态元素定位
  • 揭开内容分发网络(CDN)的神秘面纱:互联网的隐形加速器