组合guava eventbus和AWT Event线程处理的最佳方法

lan*_*ngm 11 java awt guava

当你有一个异步事件总线和fire事件时,让我们说在UI中捕获的模型中你可能有以下问题:

已注册的处理程序在工作线程中执行,但所有UI swing更改都需要在AWT事件线程中执行.这意味着您需要将所有处理程序clode包含在内EventQueue.invokeLater(...).

这看起来像很多锅炉板代码.我想知道是否有更智能的解决方案来解决这个问题.

guava事件总线的扩展如何标记在特殊线程中执行的处理程序?这可以用注释标记,例如@ExecuteWithinEDT:

class EventBusChangeRecorder {
  @Subscribe @ExecuteWithinEDT void recordCustomerChange(ChangeEvent e) {
    recordChange(e.getChange());
  }
}
Run Code Online (Sandbox Code Playgroud)

Col*_*inD 9

使用异步事件总线注册的处理程序在提供的任何Executor选择运行它们的线程上执行,而不一定是工作线程.

我所做的是创建了一个Executor在事件队列线程上运行东西的实现.这很简单:

public class EventQueueExecutor implements Executor {
  @Override public void execute(Runnable command) {
    EventQueue.invokeLater(command);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以EventBus用它创建你的:

EventBus eventBus = new AsyncEventBus(new EventQueueExecutor());
Run Code Online (Sandbox Code Playgroud)

然后所有处理程序将在事件队列线程上执行.

编辑:

转发事件的示例:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

只需订阅您的主事件总线并将所有事件发布到主事件总线,但是将所有UI组件订阅到UI事件总线.

  • 你的解决方案很好,但它带来了另一个问题:现在所有事件都在AWT内调度.在现实世界的应用程序中,我可能希望在AWT(GUI部分)内调度一些订户,而其他子订单(来自模型或其他模块)不应该在AWT内调度.否则整个异步事件总线就没有多大意义了. (2认同)

小智 1

您可以创建仅在 AWT 线程上分派的 EventBus:

EventBus mybus = new AsyncEventBus("awt",
    new Executor() {
        public void execute (Runnable cmd) {
            if (EventQueue.isDispatchThread()) {
                cmd.run();
            } else {
                EventQueue.invokeLater(cmd);
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)