Избавление от прослушивателей событий SWT - PullRequest
0 голосов
/ 21 июня 2019

Я работаю над приложением 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?

...