源代码
GitHub源代码
本文目标
实现简易版的EventBus
基本用法
现在有两个页面,MainActivity 和 TestActivity,在MainActivity中注册EventBus事件,然后在TestActivity中发射事件
public class MainActivity extends AppCompatActivity {
private TextView mTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注册
EventBus.getDefault().register(this);
// 进入测试界面
mTv = (TextView) findViewById(R.id.test_tv);
mTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,TestActivity.class);
startActivity(intent);
}
});
}
/**
* threadMode 执行的线程方式
* priority 执行的优先级
* sticky 粘性事件
*/
@Subscribe(threadMode = ThreadMode.MAIN,priority = 50,sticky = true)
public void test1(String msg){
// 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
Log.i("TAG","msg1 = "+msg);
mTv.setText(msg);
}
/**
* threadMode 执行的线程方式
* priority 执行的优先级,值越大优先级越高
* sticky 粘性事件
*/
@Subscribe(threadMode = ThreadMode.MAIN,priority = 100,sticky = true)
public void test2(String msg){
// 如果有一个地方用 EventBus 发送一个 String 对象,那么这个方法就会被执行
Log.i("TAG","msg2 = "+msg);
mTv.setText(msg);
}
@Override
protected void onDestroy() {
// 解绑
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
在TestActivity中去发射事件
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
findViewById(R.id.test_tv).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post("今天天气真晴朗");
finish();
}
});
}
}
手写之前明确几个基本概念
在手写之前一定要先弄明白EventBus中的两个字段(两个map)
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
上面这个字段是个map集合
|-- key: Event函数的参数的类(本例中是String.class)
|-- value: Subscription 的集合列表
|-- Subscription包含两个属性
|-- 一个是subscriber 订阅者(反射执行对象,本例中是MainActivity.class)
|-- 一个是SubscriberMethod 注解方法的所有属性参数值(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
private final Map<Object, List<Class<?>>> typesBySubscriber;
上面这个字段是个map集合,主要用于解绑使用
|-- key: 所有的订阅者(本例中是MainActivity.class)
|-- value: 所有订阅者里面方法的参数的class() (本例中是 String.class 的集合)
目的是在unregister()解绑中通过key(MainActivity.class)找到value(String.class),
然后在通过value(String.class)找到subscriptionsByEventType中的value()Subscription 的集合列表,
然后就可以进行移除操作了
上述两个map是在EventBus的构造方法中去实现的
public class EventBus {
// key 是 Event 参数的类(本例中是String.class)
// value 存放的是 Subscription 的集合列表
// Subscription 包含两个属性,一个是 subscriber 订阅者(反射执行对象,本例中是MainActivity.class),一个是 SubscriberMethod 注解方法的所有属性参数值
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// key 是所有的订阅者(MainActivity.class)
// value 是所有订阅者里面方法的参数的class() (本例中就是 String.class 的集合)
private final Map<Object, List<Class<?>>> typesBySubscriber;
private EventBus() {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
}
private volatile static EventBus INSTANCE = null;
public static EventBus getDefault() {
if (INSTANCE == null) {
synchronized (EventBus.class) {
if (INSTANCE == null) {
INSTANCE = new EventBus();
}
}
}
return INSTANCE;
}
}
1.EventBus.getDefault().register()
public void register(Object object) {
//第一步
ArrayList<SubscriberMethod> subscriberMethods = new ArrayList<>();
//1.先拿到object的字节码class对象
Class<?> objectClass = object.getClass();
Method[] declaredMethods = objectClass.getDeclaredMethods();
for (Method method : declaredMethods) {
//2.获取到该class对象的所有标记@Subscribe注解的函数
Subscribe annotation = method.getAnnotation(Subscribe.class);
if(annotation!=null){
// 所有的Subscribe属性 解析出来
Class<?>[] parameterTypes = method.getParameterTypes();
//3.解析被注解标记的函数成SubscriberMethod对象(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
SubscriberMethod model = new SubscriberMethod(method, parameterTypes[0], annotation.threadMode(), annotation.priority(), annotation.sticky());
//4.然后存到subscriberMethods集合中
subscriberMethods.add(model);
}
}
//第二步
//1.遍历subscriberMethods的List集合
for (SubscriberMethod method : subscriberMethods) {
subscribe(object,method);
}
}
private void subscribe(Object object, SubscriberMethod method) {
//2.按照规则存放到subscriptionsByEventType的map集合中(key:String.class value:CopyOnWriteArrayList<Subscription>)
Class<?> eventType = method.eventType;
//先从subscriptionsByEventType 的map中取一下List,如果为空则创建一个,然后在添加
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if(subscriptions==null){
subscriptions=new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType,subscriptions);
}
Subscription subscription = new Subscription(object, method);
subscriptions.add(subscription);
//第三步:
//1.typesBySubscriber的map集合也要存一份(key:MainActivity.class value:List<Class<?> String.class 的集合)
List<Class<?>> eventTypeList = typesBySubscriber.get(object);
if(eventTypeList==null){
eventTypeList=new ArrayList<>();
typesBySubscriber.put(object,eventTypeList);
}
if(!eventTypeList.contains(eventType)){
eventTypeList.add(eventType);
}
}
register的核心思路
第一步:
- 1.先拿到object的字节码class对象
- 2.获取到该class对象的所有标记@Subscribe注解的函数
- 3.解析被注解标记的函数成SubscriberMethod对象(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
- 4.然后存到subscriberMethods集合中
第二步: - 1.遍历subscriberMethods的List集合
- 2.按照规则存放到subscriptionsByEventType的map集合中(key:String.class value:CopyOnWriteArrayList<Subscription>)
第三步: - 1.typesBySubscriber的map集合也要存一份(key:MainActivity.class value:List<Class<?> String.class 的集合)
2.EventBus.getDefault().unregister()
public void unregister(Object object) {
//1.通过typesBySubscriber这个map得到所有的String.class集合
List<Class<?>> eventTypList = typesBySubscriber.get(object);
if(eventTypList!=null){
//2.遍历这个String.class集合
for (Class<?> eventType : eventTypList) {
removeObject(eventType,object);
}
}
}
private void removeObject(Class<?> eventType, Object object) {
//3.通过subscriptionsByEventType这个map获取到CopyOnWriteArrayList<Subscription>
CopyOnWriteArrayList<Subscription> subscriptionList = subscriptionsByEventType.get(eventType);
if(subscriptionList!=null){
int size = subscriptionList.size();
//4.遍历CopyOnWriteArrayList集合,然后挨个移除
for(int x=0;x<size;x++){
//5.得到Subscription,然后subscription.subscriber==object 进行比较,如果相同则移除
Subscription subscription = subscriptionList.get(x);
if(subscription.subscriber==object){
subscriptionList.remove(x);
x--;
size--;
}
}
}
}
unregister的核心思路
- 1.通过typesBySubscriber这个map得到所有的String.class集合
- 2.遍历这个String.class集合
- 3.通过subscriptionsByEventType这个map获取到CopyOnWriteArrayList<Subscription>
- 4.遍历CopyOnWriteArrayList集合
- 5.得到Subscription,然后subscription.subscriber==object 进行比较,如果相同则移除
3.EventBus.getDefault().post()
public void post(Object event) {
//1.先获取event的字节码对象,这其实就是eventType
Class<?> evenType = event.getClass();
//2.从subscriptionsByEventType中根据eventType得到Subscription 的集合列表
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(evenType);
if(subscriptions!=null){
//3.遍历这个集合
for (Subscription subscription : subscriptions) {
executeMethod(subscription,event);
}
}
}
//4.找到符合的方法调用方法的 method.invoke() 执行,要注意线程切换
private void executeMethod(final Subscription subscription, final Object event) {
SubscriberMethod subscriberMethod = subscription.subscriberMethod;
//是否在主线程
boolean isMainThread = Looper.getMainLooper() == Looper.myLooper();
switch (subscriberMethod.threadMode){
//同一个线程,在哪个线程发送事件,那么该方法就在哪个线程执行
case POSTING:
invokeMethod(subscription,event);
break;
// 在主线程中执行
case MAIN:
if(isMainThread){
invokeMethod(subscription,event);
}else{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
invokeMethod(subscription,event);
}
});
}
break;
//子线程:如果发布事件的线程是主线程,那么调用线程池中的子线程来执行订阅方法;否则直接执行;
case BACKGROUND:
if(isMainThread){
AsyncPoster.enqueue(subscription,event);
}else{
invokeMethod(subscription,event);
}
break;
//异步线程:无论发布事件执行在主线程还是子线程,都利用一个异步线程来执行订阅方法。
case ASYNC:
AsyncPoster.enqueue(subscription,event);
break;
default:
break;
}
}
/**
* 真正的反射调用方法
* @param subscription
* @param event
*/
private void invokeMethod(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber,event);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
post的核心思路
- 1.先获取event的字节码对象,这其实就是eventType
- 2.从subscriptionsByEventType中根据eventType得到Subscription 的集合列表
- 3.遍历这个集合
- 4.找到符合的方法调用方法的 method.invoke() 执行,要注意线程切换
下面的代码是一些辅助代码,核心的代码都在上面
线程池的使用
public class AsyncPoster implements Runnable {
final Subscription subscription;
final Object event;
private final static ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
public AsyncPoster(Subscription subscription, Object event) {
this.subscription = subscription;
this.event = event;
}
public static void enqueue(final Subscription subscription, final Object event) {
AsyncPoster asyncPoster = new AsyncPoster(subscription, event);
// 用线程池
EXECUTOR_SERVICE.execute(asyncPoster);
}
@Override
public void run() {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
@Subscribe注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* 是否是黏性事件
* @return
*/
boolean sticky() default false;
/**
* 优先级,值越大优先级越高
* @return
*/
int priority() default 0;
}
线程模型
public enum ThreadMode {
/**
* 同一个线程,在哪个线程发送事件,那么该方法就在哪个线程执行
*/
POSTING,
/**
* 在主线程中执行
*/
MAIN,
/**
* 子线程:如果发布事件的线程是主线程,那么调用线程池中的子线程来执行订阅方法;否则直接执行;
*/
BACKGROUND,
/**
* 异步线程:无论发布事件执行在主线程还是子线程,都利用一个异步线程来执行订阅方法。
*/
ASYNC
}
Subscription 包装类
final class Subscription {
final Object subscriber; //反射执行对象,本例中是MainActivity.class
final SubscriberMethod subscriberMethod;//方法上解析的所有信息包装类
volatile boolean active;
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
@Override
public int hashCode() {
return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
}
}
Subscription包含两个属性
|-- 一个是subscriber 订阅者(反射执行对象,本例中是MainActivity.class)
|-- 一个是SubscriberMethod 注解方法的所有属性参数值(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)
SubscriberMethod 包装类
public class SubscriberMethod {
final Method method;//method方法对象
final ThreadMode threadMode;//线程模型
final Class<?> eventType;//事件类型class
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;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
} else if (other instanceof SubscriberMethod) {
checkMethodString();
SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
otherSubscriberMethod.checkMethodString();
// Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
return methodString.equals(otherSubscriberMethod.methodString);
} else {
return false;
}
}
private synchronized void checkMethodString() {
if (methodString == null) {
// Method.toString has more overhead, just take relevant parts of the method
StringBuilder builder = new StringBuilder(64);
builder.append(method.getDeclaringClass().getName());
builder.append('#').append(method.getName());
builder.append('(').append(eventType.getName());
methodString = builder.toString();
}
}
@Override
public int hashCode() {
return method.hashCode();
}
}
注解方法的所有属性参数值的封装类(threadModel线程模型 priority优先级 sticky是否黏性 eventType事件类型class method方法对象)