当你有一个异步事件总线和火灾事件时,让我们说在UI中捕获的模型中你可能遇到以下问题:
已注册的处理程序在工作线程中执行,但所有UI swing更改都需要在AWT事件线程中执行。
这意味着您需要在EventQueue.invokeLater(...)
中包含所有处理程序clode。
这看起来像很多锅炉板代码。 我想知道是否有更智能的解决方案来解决这个问题。
guava事件总线的扩展如何标记在特殊线程中执行的处理程序?这可以用例如标注来标记,例如@ExecuteWithinEDT
:
class EventBusChangeRecorder {
@Subscribe @ExecuteWithinEDT void recordCustomerChange(ChangeEvent e) {
recordChange(e.getChange());
}
}
答案 0 :(得分:9)
使用异步事件总线注册的处理程序在所提供的Executor
选择运行它们的任何线程上执行,而不一定是工作线程。
我所做的是创建了一个Executor
的实现,它在事件队列线程上运行东西。这很简单:
public class EventQueueExecutor implements Executor {
@Override public void execute(Runnable command) {
EventQueue.invokeLater(command);
}
}
然后,您可以使用以下内容创建EventBus
:
EventBus eventBus = new AsyncEventBus(new EventQueueExecutor());
然后所有处理程序都将在事件队列线程上执行。
修改强>
转发事件的示例:
public class EventForwarder {
private final EventBus uiEventBus;
public EventForwarder(EventBus uiEventBus) {
this.uiEventBus = uiEventBus;
}
// forward all events
@Subscribe
public void forwardEvent(Object event) {
uiEventBus.post(event);
}
// or if you only want a specific type of event forwarded
@Subscribe
public void forwardEvent(UiEvent event) {
uiEventBus.post(event);
}
}
只需订阅主事件总线并将所有事件发布到主事件总线,但是将所有UI组件订阅到UI事件总线。
答案 1 :(得分:1)
您可以创建仅在AWT线程上调度的EventBus:
EventBus mybus = new AsyncEventBus("awt",
new Executor() {
public void execute (Runnable cmd) {
if (EventQueue.isDispatchThread()) {
cmd.run();
} else {
EventQueue.invokeLater(cmd);
}
}
});