一文分析EventBus-事件总线的使用方法和实现原理

本文详细介绍了 Android 中 EventBus 的使用方法,包括定义事件类、注册/取消注册、选择线程模式,特别是深入解析了 EventBus 3.0 的注册、发布和取消注册的源码流程,帮助开发者理解其底层原理。
摘要由CSDN通过智能技术生成

前言

本文主要从源码的角度来分析事件总线 EventBus 的实现原理, EventBus 是常用的消息传递的方式之一,其他常见的消息传递的方式还包括 HandlerBroadcastReceiverListener。通过本篇你在掌握 EventBus 基本使用的基础之上,能够掌握 EventBus 的实现原理。下面的框架图可以清晰的看到这一点。

一、定义事件类

作为事件的发布者,需要定义所发布的事件的类:

public class MessageEvent {
   
	private String msg;
	public MessageEvent(String msg) {
   
    this.msg = msg;
	}

	public String getMsg() {
   
    	return msg;
	}

	public void setMsg(String msg) {
   
    	this.msg = msg;
	}
}

二、注册/取消注册响应事件

作为事件的订阅者,需要把响应事件的对象注册到EventBus当中:EventBus.getDefault().register(obj)

当不需要处理某个类型的事件的时候,取消对这个事件的监听:EventBus.getDefault().unregister(obj)

三、声明和注释订阅方法,选择指定线程模式

作为事件的订阅者,需要定义事件的响应方法,方法名称可以随意取,方法的形参类型,必须和监听的事件对象类型一致:

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
   
	Toast.makeText(this, event.getMsg (),
	Toast.LENGTH_SHORT).show();
}

3.1 四种线程模式

事件订阅者可以通过注解的方式选择处理事件的方法所在的线程:

  • PostThread: 如果事件处理函数指定了线程模型为PostThread,那么事件的发布和接收处理会在同一个线程当中。

  • BackgroundThread: 如果事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的子线程中运行,如果事件发布本来就是非UI线程中发布出来 的,那么该事件处理函数直接在发布事件的线程中执行。

  • MainThread: 如果事件处理函数指定了线程模型为MainThread,那么不论事件对象是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。

  • Async: 如果事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。

3.2 黏性事件

通过注解的方式设置sticky为true,那么事件处理函数则可以处理上一次的事件对象:

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)

四、EventBus 3.0源码详解

4.1 注册流程

/**
* Registers the given subscriber to receive events. 	Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be 	annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration 	like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
   
//通过注册的对象得到其类的class对象
Class<?> subscriberClass = subscriber.getClass();
//通过类的class对象得到此对象的订阅方法列表
List<SubscriberMethod> subscriberMethods = 	subscriberMethodFinder.findSubscriberMethods(subscriberClass);
	synchronized (this) {
   
    	for (SubscriberMethod subscriberMethod :subscriberMethods) {
   
        	//线程同步,遍历订阅方法列表,注册每一个订阅方法
        	subscribe(subscriber, subscriberMethod);
    	}
	}
}

代码subscriberMethodFinder.findSubscriberMethods(subscriberClass)获取订阅方法列表具体如下:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
   
	//在缓存中查找此class对象对应的订阅方法列表
  	List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
  	if (subscriberMethods != null) {
   
      return subscriberMethods;
  	}
  //是否忽略注解器生成的MyEventBusIndex类
  if (ignoreGeneratedIndex) {
   
    	//通过反射机制得到订阅者类class对象对应的订阅事件方法列表
    	subscriberMethods = findUsingReflection(subscriberClass);
  } else {
   
  		//从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法列表
    	subscriberMethods = findUsingInfo(subscriberClass);
	}
  if (subscriberMethods.isEmpty()) {
   
      throw new EventBusException("Subscriber " + subscriberClass
              + " and its super classes have no public methods with the @Subscribe annotation");
  } else {
   
      //缓存此class对象的订阅方法列表
      METHOD_CACHE.put(subscriberClass, subscriberMethods);
      return subscriberMethods;
  }
}

通过反射机制获取订阅方法列表:

private 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值