Игнорирование событий, которые запускаются неоднократно - PullRequest
0 голосов
/ 11 мая 2011

У меня есть код, который отвечает на PropertyChangeEvent. Проблема с этим событием заключается в том, что его можно запустить несколько раз подряд или нет вообще. Невозможно предсказать, будет ли это событие запускаться один или несколько раз, и я не контролирую, как это событие происходит. Я бы хотел, чтобы слушатель события был запущен только один раз.

Мое решение этой проблемы - использовать класс, который я написал, под названием DelayedRunnable. Я завернул слушателя в DelayedRunnable. Когда событие запускается впервые, слушатель должен быть запущен через одну секунду - количество времени, которое я выбрал произвольно. Последующие срабатывания событий игнорируются до тех пор, пока не пройдет одна секунда. Вот код для DelayedRunnable:

public class DelayedRunnable implements Runnable {
    final Runnable                 runnable;
    final int                      delayAmount;
    final TimeUnit                 delayUnit;
    final ScheduledExecutorService service         = new ScheduledThreadPoolExecutor(1);
    final Runnable                 executeRunnable = new ExecuteRunnable();
    final AtomicBoolean            scheduled       = new AtomicBoolean(false);

    public DelayedRunnable(Runnable runnable, int delayAmount, TimeUnit delayUnit) {
        if (runnable == null)
            throw new IllegalArgumentException("runnable == null");
        this.runnable = runnable;
        this.delayAmount = delayAmount;
        this.delayUnit = delayUnit;
    }

    public void run() {
        if (!scheduled.compareAndSet(false, true))
            return;
        service.schedule(executeRunnable, delayAmount, delayUnit);
    }

    class ExecuteRunnable implements Runnable {
        public void run() {
            runnable.run();
            scheduled.set(false);
        }
    }
}

Когда я заключаю слушателя в DelayedRunnable, он вызывается только один раз. Вспомогательное преимущество DelayedRunnable состоит в том, что код слушателя не выполняется в Swing EDT, поскольку код слушателя стоит дорого.

Однако я обнаружил, что иногда слушатель никогда не вызывается, возможно, из-за проблем параллелизма в DelayedRunnable. Когда я перезапускаю приложение, слушатель снова волшебным образом работает. Как и следовало ожидать, я не могу воспроизвести ситуации, когда DelayedRunnable не работает из-за природы параллельного программирования. Кроме того, ограничение по времени в одну секунду совершенно произвольно. На некоторых компьютерах одной секунды может быть недостаточно. На других компьютерах одна секунда слишком длинная. Не существует простого способа установить ограничение по времени.

У меня есть два вопроса:

  • Кто-нибудь знает о проблемах с DelayedRunnable, которые я не вижу?

  • Есть ли более элегантный способ решения этой проблемы, чем использование этого DelayedRunnable подхода?

Ответы [ 3 ]

2 голосов
/ 11 мая 2011

Одна вещь, с которой вам следует быть осторожным, это делать работу за пределами EDT.поскольку фактический исполняемый объект запускается в новом потоке (внутри службы исполнителя), он не может выполнять какую-либо работу с графическим интерфейсом напрямую.

возможно, что один из ваших исполняемых файлов зависает, и поэтому любые последующие исполнения блокируются.

0 голосов
/ 12 мая 2011

Как упоминает jtahlborn, работа с графическим интерфейсом должна выполняться в очереди событий. Убедитесь, что вся работа с графическим интерфейсом заключена в EventQueue.invokeAndWait или EventQueue.invokeLater .

На самом деле, в зависимости от характера того, как генерируются события, вы можете полностью избежать механизма задержки, используя EventQueue.invokeLater, потому что запускаемый объект, который нужно вызвать, помещается в конец очереди. Если все множественные обратные вызовы событий добавляются в очередь до запуска первого обратного вызова, вы можете быть уверены, что добавленный в очередь runnable с invokeLater не увидит никаких последующих событий. Затем вы можете использовать флаг, аналогичный тому, что вы уже делаете в DelayedRunnable, чтобы гарантировать, что вы добавляете только runnable для первого события.

0 голосов
/ 11 мая 2011

Прослушиватель событий AWT будет запущен раньше других слушателей, поэтому вы можете сначала отфильтровать событие там. с чем-то вроде:

something like Container c;
.
.
.
c.addAWTEventListener(new AWTEventListener()
{
    public void eventDispatched(AWTEvent e)
    {
       if(! e instanceof YOUR_EVENT_TYPE)
       return;
       //code to filter here
       e.consume() //to remove if not in time bounds   
    }
});

см. http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/AWTEventListener.html для использования

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...