EventBus使用
1、eventbus简介
eventbus是Android事件发布-订阅总线,简化了活动片段、线程、服务等之间的通信,代码更少,质量更好,可以避免由于使用广播通信而带来的诸多不便。具体使用可以参考:https://github.com/greenrobot/EventBus,我这里主要是简单讲解eventBus的代码逻辑思想,以及自己简单实现一个EventBus
2、Subscribe 介绍
@Subscribe采用运行时注解,且注解只能用在函数上,默认的threadmode为posting
3、threadMode介绍
POSTING | 默认的模式,开销最小的模式,因为声明为POSTING的订阅者会在发布的同一个线程调用,发布者在主线程那么订阅者也就在主线程,反之亦,避免了线程切换,如果不确定是否有耗时操作,谨慎使用,因为可能是在主线程发布 |
MAIN | 主线程调用,视发布线程不同处理不同,如果发布者在主线程那么直接调用(非阻塞式),如果发布者不在主线程那么阻塞式调用 |
MAIN_ORDERED | 和MAIN差不多,主线程调用,和MAIN不同的是他保证了post是非阻塞式的(默认走MAIN的非主线程的逻辑,所以可以做到非阻塞) |
BACKGROUND | 在子线程调用,如果发布在子线程那么直接在发布线程调用,如果发布在主线程那么将开启一个子线程来调用,这个子线程是阻塞式的,按顺序交付所有事件,所以也不适合做耗时任务,因为多个事件共用这一个后台线程 |
ASYNC | 在子线程调用,总是开启一个新的线程来调用,适用于做耗时任务,比如数据库操作,网络请求等,不适合做计算任务,会导致开启大量线程 |
4、register介绍
通过getDefault获取EventBus实例,这是一条默认的事件总线,通过单例模式实现,其构造函数是Public的也可以通过new的形式来创建多条事件总线
register方法
/**
* 注册
*/
public void register(Object subscriber) {
Class<?> aClass = subscriber.getClass();
//从缓存中读取
List<SubscribleMethod> subscribleMethods = cacheMap.get(subscriber);
//缓存中没有
if (null == subscribleMethods) {
subscribleMethods = getSubscribleMethods(subscriber);
cacheMap.put(subscriber, subscribleMethods);
}
}
getSubscribleMethods方法
/**
* 遍历接收事件的方法
*
* @param subscriber
* @return
*/
private List<SubscribleMethod> getSubscribleMethods(Object subscriber) {
List<SubscribleMethod> list = new ArrayList<>();
Class<?> aClass = subscriber.getClass();
while (aClass != null) {
//判断分类是在那个包下,(如果是系统的就不需要)
String name = aClass.getName();
if (name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("android.")
|| name.startsWith("androidx.")) {
break;
}
//对象表示的类或接口声明的所有方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
//获取我们自己定义的标签
Subscribe annotation = declaredMethod.getAnnotation(Subscribe.class);
if (annotation == null) {
continue;
}
//获得方法参数类型
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
//eventbus 是能有一个参数
if (parameterTypes.length != 1) {
throw new RuntimeException("eventbusz只能接收一个参数");
}
//符合要求的
ThreadMode threadMode = annotation.threadMode();
SubscribleMethod subscribleMethod = new SubscribleMethod(declaredMethod,threadMode,parameterTypes[0]);
list.add(subscribleMethod);
}
//获取父类 activity---->baseActivity----->
aClass = aClass.getSuperclass();
}
return list;
}
5、post简介
我这里就只处理了MAIN、ASYNC、POSTING线程之间的切换,遍历前面register的activity中的所有@Subscribe方法,在post方法中根据threadMode线程来切换相应的线程
/**
* 发送数据
* @param obj
*/
public void post(final Object obj) {
Set<Object> objects = cacheMap.keySet();
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()){
//拿到注册类
final Object next = iterator.next();
//获取类中所有添加注解的方法
List<SubscribleMethod> subscribleMethods = cacheMap.get(next);
for (final SubscribleMethod subscribleMethod : subscribleMethods) {
if (subscribleMethod.getEventType().isAssignableFrom(obj.getClass())){
switch (subscribleMethod.getThreadMode()){
case MAIN:
//如果接收方法在主线程执行的情况
if(Looper.myLooper() == Looper.getMainLooper()){
invoke(subscribleMethod, next, obj);
} else {
//post方法执行在子线程中,接收消息在主线程中
handler.post(new Runnable() {
@Override
public void run() {
invoke(subscribleMethod, next, obj);
}
});
}
break;
//接收方法在子线程种情况
case ASYNC:
//post方法执行在主线程中
if(Looper.myLooper() == Looper.getMainLooper()){
executorService.execute(new Runnable() {
@Override
public void run() {
invoke(subscribleMethod, next, obj);
}
});
} else {
//post方法执行在子线程中
invoke(subscribleMethod, next, obj);
}
break;
case POSTING:
break;
}
}
}
}
}
/**
* 执行方法
* @param subscribleMethod
* @param next
* @param obj
*/
private void invoke(SubscribleMethod subscribleMethod, Object next, Object obj) {
Method method = subscribleMethod.getMethod();
try {
method.invoke(next, obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
6、unregister方法
/**
* 取消注册
*/
public void unregister(Object subscriber) {
List<SubscribleMethod> subscribleMethods = cacheMap.get(subscriber);
if (subscribleMethods!=null){
cacheMap.remove(subscriber);
}
}
总结
这里简单实现了eventBus的register、post、unregister方法,具体代码下载地址:demo