参考:
EventBus的介绍部分参考:https://www.jianshu.com/p/e7d5c7bda783
DIY一个EventBus,熟悉ThreadMode.MAIN模式下的订阅、发布流程,参考的网易云课堂官方、彭锡老师主讲的公开课,但原课程已下架。
EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,它简化了应用程序内各个组件之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
EventBus有四种线程模式,posting、main、backgroud、async,他们的意义如下:
一、POSTING:默认,表示事件处理函数的线程跟发布事件的线程在同一个线程。
二、MAIN:表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
三、BACKGROUND:表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程(UI线程),那么事件处理函数将会开启一个后台线程,如果果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
四、ASYNC:表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。
下面我们通过一个简单的例子来熟悉Event Bus的使用
一、添加依赖,略;
二、订阅者注册和添加接收事件的方法,在接收事件方法中对事件进行处理。EventBus 3.0之后,被Subscribe注解的方法即是事件的接收方法。
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void subscribe(String s) { tv.setText(s); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); }
三、发布者发布事件
EventBus.getDefault().post("eventbus_2");
通过自己写一个EventBus来熟悉流程。这个EventBus很简单,只有一种线程模式:main,不支持黏性事件和优先级,判断过程也及其简单。
public enum ThreadMode { POSTING, MAIN, }
二、创建注解
EventBus 3.0以上,通过注解标识事件的接收方法。注解有ThreadMode/线程模式、sticky/粘性、property/消息等级等参数,我们这里只关注ThreadMode。注意@Retention(RetentionPolicy.RUNTIME)。
// 此注解至作用于方法 @Target(ElementType.METHOD) // *,表示jvm加载class文件后,注解依然存在。没有这个对注解(Subscribe)的注解,后面获取注解将返回null @Retention(RetentionPolicy.RUNTIME) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; }
对订阅者的事件接收方法进行封装。我们可以看一下接收方法,有哪些重要的信息,把这些信息抽象出来即可。1、方法本身;2、标识此方法是事件接收方法的注解,这个注解的参数是ThreadMode(黏性、优先级忽略);3、接收方法的参数:事件类型。所以事件的接收方法类,就是这三个成员变量及Getter、Setter,还有就是构造方法。
public class SubscribeMethod { // 线程模式 ThreadMode threadMode; // 事件的接收方法本身 Method method; // 事件的接收方法的参数,事件类型 Class eventType; /** 构造方法和Setter、Getter略 */ }
前面只是构造对象类的话,这个就是EventBus的核心了:订阅者注册和发布者发布事件。注意:EventBus必须是单例。
1、注册过程。注册过程是把订阅者(main模式的Activity)和事件的接收方法以键值对形式缓存起来。核心是找到事件的接收方法,一个重要的特征是被Subscribe注解了,然后可以在根据参数、返回值,还有其他条件,进一步判断。
注意:tempMethod.getAnnotation(Subscribe.class),Subscribe必须被@Retention(RetentionPolicy.RUNTIME)注解,否则这个方法返回null。
HashMap<Object, ArrayList<SubscribeMethod>> methodMap = new HashMap<>(); // 找到哪些方法(用于接收) public void register(Object subscriber) { // 接收事件的方法(可能不止一个) ArrayList<SubscribeMethod> methods = methodMap.get(subscriber); if (methods == null) { methods = findEventReceiverMethod(subscriber); methodMap.put(subscriber, methods); } } private ArrayList<SubscribeMethod> findEventReceiverMethod(Object obj) { ArrayList<SubscribeMethod> methods = new ArrayList<>(); Class clz = obj.getClass(); // 获取当前类的方法,getMethods()获取当前类和父类的方法 Method[] methodArray = clz.getDeclaredMethods(); // 当前类的方法 for (Method tempMethod : methodArray) { Subscribe subscribe = tempMethod.getAnnotation(Subscribe.class); // 过滤注解 if (subscribe == null) { continue; } // EventBus must return null Type returnType = tempMethod.getGenericReturnType(); // EventBus must has only one param Class[] paramTypes = tempMethod.getParameterTypes(); SubscribeMethod tempSubscribeMethod = new SubscribeMethod(); tempSubscribeMethod.setEventType(paramTypes[0]); // 这里可以根据不同的线程模式 tempSubscribeMethod.setThreadMode(subscribe.threadMode()); tempSubscribeMethod.setMethod(tempMethod); methods.add(tempSubscribeMethod); } return methods; }
2、发布者发布,通过反射的方式调用订阅者的事件接收方法。
标准情况下,这里会判断线程模式,来确定在哪个线程,回调执行事件的接收方法。
public void post(Object event) { Set<Object> keySet = methodMap.keySet(); for (Object key : keySet) { ArrayList<SubscribeMethod> methodLs = methodMap.get(key); for (SubscribeMethod subscribeMethod : methodLs) { // 不要所有的都接受,通过判断发布事件 if (subscribeMethod.getEventType().isAssignableFrom(event.getClass())) { try { subscribeMethod.getMethod().invoke(key, event); } catch (Exception e) { e.toString(); } } } } }
原文:https://www.cnblogs.com/hellodingc/p/12639570.html