Я работаю над приложением SWT Desktop, где мы используем много слушателей для наших различных виджетов. В настоящее время я пытаюсь управлять жизненным циклом этих слушателей, и хотя я пришел к решению, мне было любопытно, пропустил ли я что-то или мог бы сделать что-то лучше.
Ситуация следующая:
При выполнении привязки данных в соответствии с информацией об атрибутах создается несколько SWTEventListener (s) (Verify, Modify, Focus ...). По умолчанию они просто добавляются в таблицу событий виджета, но поскольку удаление слушателя требует определенного экземпляра, известного как:
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<>();
Это не сработало. Абстрактный класс был объявлен как Listener, так что widget.removeListener(...)
примет его, и он это сделал, но все эти SWTEventListeners были типизированными слушателями, то есть они действительно содержали в себе точного слушателя, но им не удавалось выполнить if в EventTable.unhook * 1013. *
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
Таким образом, если происходит сбой, слушатель не удаляется.
Однако у 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?