我正在SWT桌面应用程序上工作,在该应用程序中,我们为各种小部件使用了很多侦听器。目前,我正在尝试管理这些侦听器的生命周期,当我找到解决方案时,我很好奇自己是否错过了某些事情,或者是否可以做得更好。
情况如下:
执行数据绑定时,根据属性信息,将创建多个SWTEventListener(验证,修改,焦点...)。默认情况下,它们只是添加到窗口小部件的事件表中,但是因为删除侦听器需要一个特定的实例,所以:
widget.removeListener(SWT.Verify, formatVerifyListener);
我们决定将所有侦听器保存在一个多图(Map<Widget, List<AbstractDataBindingListener>
)中,当我们处理此特定上下文时,我们尝试删除所述侦听器:
for(Entry<Widget, List<AbstractDataBindingListener>> entry : boundWidgets.entrySet()) {
for (AbstractDataBindingListener listener : entry.getValue()) {
entry.getKey().removeListener(listener.getSwtEvent, listener);
}
entry.getValue().clear();
}
boundWidgets.clear(); // rendundant?
boundWidgets = new HashMap<>();
这不起作用。抽象类被声明为侦听器,因此widget.removeListener(...)
会接受它,并且确实接受了,但是所有这些SWTEventListeners都是Typed侦听器,也就是它们确实包含了确切的侦听器,但它们在EventTable.unhook中的if会失败。
public void unhook (int eventType, Listener listener) {
if (types == null) return;
for (int i=0; i<types.length; i++) {
if (types [i] == eventType && listeners [i] == listener) {
remove (i);
return;
}
}
}
因为:
listeners [i] == listener
// listeners [i] -> the listener I want removed
// listener -> typed listener, different from listener [i]
// but it wraps the correct listener
如果if失败,则不会删除侦听器。
但是Widget确实有一种可以正常工作的方法
protected void removeListener (int eventType, SWTEventListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook (eventType, listener);
}
// EventTable unhook
public void unhook (int eventType, SWTEventListener listener) {
if (types == null) return;
for (int i=0; i<types.length; i++) {
if (types [i] == eventType) {
if (listeners [i] instanceof TypedListener) {
TypedListener typedListener = (TypedListener) listeners [i];
if (typedListener.getEventListener () == listener) {
remove (i);
return;
}
}
}
}
}
但是,我当然无法访问它。访问它的唯一方法是使用.removeVerifyListener
,.removeFocusListener
,.removeModifyListener
最终的解决方案是创建一个抽象的dispose方法,并强制每个侦听器都拥有它们所附加的窗口小部件的副本(希望没有人将它们附加到其他窗口小部件,并且不能正确更新内容),以便他们可以将自己删除:
public class FloatFormatterVerifyListener extends AbstractDataBindingListener implements VerifyListener {
// ...
/** {@inheritDoc} */
@Override
public void dispose() {
for (Widget widget : boundWidgets)
if (widget != null && !widget.isDisposed()) {
widget.removeVerifyListener(this);
}
}
}
虽然这可行,但恕我直言有点儿优雅……它不是万无一失的。仍然可以将widget.addVeifyListener(floatFormatterVerifyListener)应用于另一个窗口小部件,并且处理对该窗口小部件不起作用。添加它的人还应该保存侦听器的实例并手动处理它。
但是大多数情况与上述情况相似,我们在列表中有许多不同类型的侦听器,每个侦听器都需要自己的.remove[Type]Listener
。
那有什么解决方案?我们是否应该始终将实际的侦听器(实现VerifyListener)隐藏为私有内部类,并管理由负责跟踪小部件并能够正确处理自身的父类添加它们,或者还有另一种方法不需要反射或instanceof?