Как бороться с моделью потоков JavaFX и большими изменениями данных - PullRequest
1 голос
/ 29 июня 2019

У меня есть ObservableList «Треков», отображаемых на TableView. Содержимое ObservableList основано на метаданных, считанных с диска.

Иногда мне приходится добавлять или удалять большие порции данных из ObservableList. Некоторые изменения списка могут занять пять секунд или дольше (например, путем удаления 5000 определенных дорожек из списка 50000).

JavaFX требует, чтобы любые изменения в ObservableList, поддерживающие TableView, выполнялись только в потоке JavaFX. Если я выполняю 5-секундную транзакцию в потоке JavaFX, пользовательский интерфейс программы зависнет на 5 секунд, что является недопустимым поведением.

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

Это работает достаточно хорошо, но создает другие проблемы, с которыми у меня возникают проблемы при управлении или инкапсуляции, и это заставляет меня подозревать, что это не очень хорошее решение.

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

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

Вопрос сводится к следующему: Какая структура лучше всего подходит для управления изменениями в большом списке объектов, которые должны отображаться в JavaFX TableView?

1 Ответ

1 голос
/ 01 июля 2019

Решение, которое работает хорошо, выглядит примерно так:

  1. Создайте ObservableList с именем items, который является каноническим набором данных.
  2. Рабочий поток может изменить items по желанию.
  3. Добавить прослушиватель изменений в items. Когда изменения передаются элементам, запишите, что это за изменение, и поместите его в очередь с именем pendingChanges.
  4. Создайте второй ObservableList с именем displayCache, который представляет собой набор данных, отображаемый в JavaFX.
  5. Через регулярные и небольшие промежутки времени поток JavaFX извлекает изменения из pendingChanges и применяет их к displayCache.

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

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

Это обратное предыдущему решению. Я делал displayCache канонический набор данных, который создал множество других проблем. Имея отдельный набор данных вне JavaFXThread, который можно обновлять в режиме реального времени, я могу обойти все эти проблемы и установить задержку там, где она есть - между набором данных и пользовательским интерфейсом.

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