我的问题与Guava EventBus dispatching完全相同,但是尽管基本问题相似,但我试图解决的问题使我陷入了黑暗。
我有2个事件被背对背触发。完成所有处理程序后,第二个事件取决于第一个事件的最终状态。只有在第一个事件未取消的情况下,它才应触发。问题在于这两个事件都是从另一个事件的处理程序中触发的。
因此,尽管我不在乎谁听第一嵌套事件,但我确实在乎他们要说些什么。我已经离开了事件和Guava的EventBus旨在解决的问题空间了吗?
考虑:
public void parentEventHandler(ParentEvent parentEvent) {
Object nestedEvent = createNestedEvent();
eventBus.post(nestedEvent);
if(nestedEvent.isCancelled()) {
return;
}
Object anotherNestedEvent = createOtherNestedEvent();
eventBus.post(anotherNestedEvent);
}
我所期望的:
1. parentEvent is posted
2. parentEventHandler is called
3. nestedEvent is posted
4. handlers of nestedEvent are called
5. finished handling nestedEvent
6. if statement checks for cancel state of nestedEvent
7. anotherNestedEvent is posted if nestedEvent not cancelled
8. handlers of anotherNestedEvent are called
9. finished handling anotherNestedEvent
10 finished handling parentEvent
发生了什么事
1. parentEvent is posted
2. parentEventHandler is called
3. nestedEvent is posted
4. if statement checks for cancel state of nestedEvent (defaults to false)
5. anotherNestedEvent is posted
6. finished handing parentEvent
7. handlers of nestedEvent are called
8. nestedEvent is cancelled (too late now)
9. finished handling nestedEvent
10 handlers of anotherNestedEvent are called
11 finished handling anotherNestedEvent
在第8点,无论处理程序是否取消该事件,第二个事件都已经在队列中,因为取消检查默认为false。番石榴的EventBus坚持在开始下一个事件之前完成其当前处理程序的运行,我确定它有用途,但不是我想要的。
尝试入侵:
我注意到Guava有一个InstantDispatcher(https://github.com/google/guava/blob/master/guava/src/com/google/common/eventbus/Dispatcher.java#L179)的实现,该实现可以在事件发生时发布事件,这与保存事件的行为相反,直到默认PerThreadQueuedDispatcher的所有订阅者都处理了当前事件为止( https://github.com/google/guava/blob/master/guava/src/com/google/common/eventbus/Dispatcher.java#L73。
但是,这些其他调度程序是私有程序包,EventBus上没有公共API可以更改调度程序以使用。派生Guava并将https://github.com/google/guava/blob/master/guava/src/com/google/common/eventbus/EventBus.java#L122和L136的默认调度程序更改为Dispatcher.immediate()
,在另一个版本号下在本地重新安装Guava,并大肆破坏该自定义构建到我的项目中,在应用程序hasn中观察到的事件行为根本没有改变。现在我完全迷路了。
是否可以通过Guava的EventBus来实现严格的LIFO事件分配,或者我应该关注的是另一种范式,而不是可以取消事件并经常嵌套在其他事件处理程序中的有意义的事件?我不在乎有多少和哪些订阅者收听事件,但是我确实想知道他们对事件有何评论(即他们是否决定取消事件)。该应用程序完全是单线程的。
答案 0 :(得分:2)
如果您使用的是“常规” EventBus
,则可以通过创建辅助事件来使其正常工作。
添加接口InternalEventCallback
和类InternalEventCallbackHandler
:
interface InternalEventCallback {
void run();
}
class InternalEventCallbackHandler {
@Subscribe
public void internalEventHandler(InternalEventCallback r){
r.run();
}
}
在创建EventBus
的地方,注册InternalEventCallbackHandler
:
eventBus.register(new InternalEventCallbackHandler());
然后在您的parentEventHandler
中执行以下操作:
@Subscribe
public void parentEventHandler(ParentEvent parentEvent) {
NestedEvent nestedEvent = createNestedEvent();
eventBus.post(nestedEvent);
eventBus.post(new InternalEventCallback() {
@Override
public void run() {
if(nestedEvent.isCancelled()) {
return;
}
Object anotherNestedEvent = createOtherNestedEvent();
eventBus.post(anotherNestedEvent);
}
});
}
修改:
如果将AsyncEventBus
与“直接执行器”一起使用,则可以得到与上例相同的行为,但是没有InternalEventCallback
和InternalEventCallbackHandler
EventBus eventBus = new AsyncEventBus(MoreExecutors.newDirectExecutorService());
答案 1 :(得分:0)
结果是我的自定义Guava构建被主机应用程序中已经捆绑的较旧版本的Guava覆盖了(当然,确实如此)。我最终通过代码应用了该hack(可能对版本更改不是很有弹性):
public GuavaEventService() {
this.bus = new EventBus();
try {
Field dispatcherField = EventBus.class.getDeclaredField("dispatcher");
dispatcherField.setAccessible(true);
Class<?> dispatcherClass = dispatcherField.get(this.bus).getClass().getSuperclass();
Method immediateDispatcher = dispatcherClass.getDeclaredMethod("immediate");
immediateDispatcher.setAccessible(true);
dispatcherField.set(this.bus, immediateDispatcher.invoke(null));
} catch (Exception ex) {
throw new IllegalStateException("Failed to initialize event service dispatcher: " + ex.getMessage());
}
}
但是,艾登在他的答案编辑中提出了一个更简洁的异步事件总线替代方案:
EventBus eventBus = new AsyncEventBus(MoreExecutors.newDirectExecutorService());