项目链接
概述
在 跟我一起写EventBus(一)
里实现了一个非常粗糙的EventBus
,在 跟我一起写EventBus(二)
,又增加了基类中注册和事件类型宽泛匹配的功能,这一节需要加上在不同线程分发事件的功能,下面会详细解释事件的分发流程。
在不同的线程分发事件(即在指定的线程调用使用了 @BusReceiver
注解的事件接收器的方法),主要支持三种线程:
- 事件发送者(调用
post(event)
方法)所在的线程,这是上一版的处理方式,对于大部分场景来说,这都不太合适;
- 主线程(UI线程),对Android来说,异步任务完成后一般是更新界面,而更新UI必须在主线程中操作,所以这是一个主要用例;
- 独立线程,另外维护一个线程池,在单独的线程中处理事件,这个适用于需要在事件接收器方法中进行耗时操作的情况,可以避免堵塞发送者线程或主线程。
Scheduler接口
在不同的线程分发事件,需要一个调度器,这里定义一个简单的调度器 Scheduler
接口:
1 2 3 4 5
| interface Scheduler { void post(Runnable runnable); }
|
调度器的作用很简单,就是执行一个 Runnable
定义的任务,可以是同步的、异步的,具体看实现类的定义。
发送者线程分发
发送者线程分发是最简单的,直接调用事件接收器的方法即可,使用 Scheduler
接口的实现就是:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class SenderScheduler implements Scheduler { private Bus mBus;
public SenderScheduler(final Bus bus) { mBus = bus; }
@Override public void post(final Runnable runnable) { runnable.run(); } }
|
主线程分发
针对Android系统的特点,要在主线程分发事件,需要用到 Handler
,再定义一个使用Handler的调度器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class HandlerScheduler implements Scheduler { private Bus mBus; private Handler mHandler;
public HandlerScheduler(final Bus bus, final Handler handler) { mBus = bus; mHandler = handler; }
@Override public void post(final Runnable runnable) { mHandler.post(runnable); } }
|
有了 HandlerScheduler
这个类,要实现在主线程分发事件就简单了:
1 2 3
| static Scheduler getMainThreadScheduler(final Bus bus) { return new HandlerScheduler(bus, new Handler(Looper.getMainLooper())); }
|
独立线程分发
要在独立线程分发事件,可以使用并发框架里的 Executor
,不用额外的维护线程的创建和终止:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class ExecutorScheduler implements Scheduler { private Bus mBus; private Executor mExecutor;
public ExecutorScheduler(final Bus bus) { mBus = bus; mExecutor = Executors.newCachedThreadPool(); }
@Override public void post(final Runnable runnable) { mExecutor.execute(runnable); } }
|
Scheduler使用
定义
最后创建三种调度器的工厂方法,调度器这边就准备好了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public final class Schedulers {
public static Scheduler sender(final Bus bus) { return new SenderScheduler(bus); }
public static Scheduler getMainThreadScheduler(final Bus bus) { return new HandlerScheduler(bus, new Handler(Looper.getMainLooper())); }
public static Scheduler thread(final Bus bus) { return new ExecutorScheduler(bus); } }
|
事件模式
在Bus
类中使用Enum定义三种事件分发模式,在Android应用中,绝大部分的事件处理都是更新界面,因为这里把主线程分发定为默认模式:
1 2 3 4 5 6 7 8 9 10 11
| * 事件发送模式: * * Sender - 在发送者的线程调用@BusReceiver/onEvent方法 * Main - 在主线程调用@BusReceiver/onEvent方法(默认为此模式) * Thread - 在一个单独的线程调用@BusReceiver/onEvent方法 */ public enum EventMode {
Sender, Main, Thread }
|
使用方法
在事件接收器方法中使用mode指定分发模式,默认是主线程分发,示例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void onEvent0(String event){ }
@BusReceiver(mode= EventMode.Main) public void onEvent1(String event){ }
@BusReceiver(mode= EventMode.Sender) public void onEvent2(String event){ }
@BusReceiver(mode= EventMode.Thread) public void onEvent3(String event){ }
|
事件分发流程
目标调用 Bus.getDefault().register(target)
的时候,查找目标对象中包含的事件接收器方法,然后构造 MethodInfo
对象和 Subscriber
对象,保存在Map中,同时保存事件类型和 Subscriber
直接的对应关系,发送者调用 post(event)
时会从Map中查找事件对应的订阅者,然后根据事件分发模式使用 Scheduler
分发事件,大概流程就是这样的,下面是几个重要的数据结构。
EventEmitter
Scheduler
接受的是 Runnable
参数,因此我们实现一个事件发送器类 EventEmitter
,它实现了 Runnable
接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class EventEmitter implements Runnable { private static final String TAG = Bus.TAG;
public final Bus bus; public final Object event; public final Subscriber subscriber; public final Bus.EventMode mode;
public EventEmitter(final Bus bus, final Object event, final Subscriber subscriber) { this.bus = bus; this.event = event; this.subscriber = subscriber; this.mode = subscriber.mode; }
@Override public void run() { try { subscriber.invoke(event); } catch (Exception e) { e.printStackTrace(); } }
|
Subscriber
Subscriber
类保存事件类型,事件接收器方法和事件目标之间的关系,定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Subscriber { public final MethodInfo method; public final Object target; public final Class<?> targetType; public final Class<?> eventType; public final Bus.EventMode mode; public final String name;
public Subscriber(final MethodInfo method, final Object target) { this.method = method; this.target = target; this.eventType = method.eventType; this.targetType = method.targetType; this.mode = method.mode; this.name = method.name; }
public Object invoke(Object event) throws InvocationTargetException, IllegalAccessException { return this.method.method.invoke(this.target, event); }
}
|
MethodInfo
MethodInfo
保存通过注解或方法名查找到的事件接收器方法的信息,包含 Method
对象和参数类型(也就是接受的事件类型),还有注解指定的分发模式,定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class MethodInfo { public final Method method; public final Class<?> targetType; public final Class<?> eventType; public final String name; public final Bus.EventMode mode;
public MethodInfo(final Method method, final Class<?> targetClass, final Bus.EventMode mode) { this.method = method; this.targetType = targetClass; this.eventType = method.getParameterTypes()[0]; this.mode = mode; this.name = targetType.getName() + "." + method.getName() + "(" + eventType.getName() + ")"; } }
|
分发事件
发送者调用 post(event)
方法时, Bus
会找到所有可能的接受者,然后构造 EventEmitter
对象,调用 sendEvent(emitter)
方法根据接受者指定的分发模式分发每一个事件,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void sendEvent(EventEmitter emitter) { if (EventMode.Sender.equals(emitter.mode)) { mSenderScheduler.post(emitter); } else if (EventMode.Main.equals(emitter.mode)) { if (Helper.isMainThread()) { mSenderScheduler.post(emitter); } else { mMainScheduler.post(emitter); } } else if (EventMode.Thread.equals(emitter.mode)) { mThreadScheduler.post(emitter); } }
|
总结
以上就是在发送者线程、主线程、独立线程分发事件的全过程,下一节会介绍事件类型的模糊匹配和缓存优化,还有扩展功能和高级用法。
系列文章
Comments