SwingWorker: создание компонентов Swing в рабочем потоке и добавление в EDT

1

Согласно SwingWorker Javadoc:

При написании многопоточного приложения с использованием Swing существуют два ограничения:

  • Затраты времени на выполнение задач не должны выполняться в разделе "Диспетчер событий". В противном случае приложение перестает отвечать на запросы.
  • Компоненты Swing должны быть доступны только в разделе "Диспетчер событий".

Таким образом, при использовании SwingWorker мы должны обращаться к компонентам Swing только в методах done() и process().

Итак, я создал пример приложения, которое загружает 3000 строк из базы данных в кусках, каждый фрагмент с 50 строками и отображает его.

SwingWorker<List<Person>, Person> worker = 
   new SwingWorker<List<Person>, Person>() {

      protected List<Person> doInBackground() {
         List<Person> data = new ArrayList<>();
         while (hasMoreData()) {
            List<Person> chunk = loadFiftyRows();
            data.addAll(chunk);
            publish(chunk);
         }
         return data;
      }

      protected void process(List<Person> chunks) {
         for (Person person : chunks) {
            container.add(createPanelFor(person));
         }
         container.revalidate();
         container.repaint();
      }

   };
worker.execute();

Так как, все качели доступа должны быть сделаны на EDT, я создаю новые экземпляры JPanel для каждого person в методе process(). Но при запуске приложение довольно тяжелое. Он замерзает и реагирует на события во время загрузки данных, довольно поздно.

Хотя мы публикуем по 50 строк за раз, размер блока увеличивается, когда метод метода process() вызывается на EDT, иногда на 1000 строк. Я думаю, что это причина задержки, создавая 1000 экземпляров JPanel на EDT!

Я чувствую, создание 1000 новых экземпляров JPanel также довольно тяжелая задача, которая должна быть выполнена на EDT. Итак, не можем ли мы создать эти экземпляры JPanel в doInBackground(), сохранить его в коллекции, а затем добавить те уже созданные экземпляры JPanel в container в методе process?

Но это будет противоречить утверждению: "Компоненты Swing должны быть доступны только в разделе" Диспетчер событий ""!

Имеет ли это выражение выражение " Существующие компоненты Swing", которые были добавлены в иерархию компонентов Swing, а не недавно созданные компоненты Swing?

  • 1
    3000 панелей это довольно большое количество. Вам, вероятно, следует использовать JTable или, по крайней мере, использовать ту же стратегию, что и та, которую он использует: использовать один компонент рендеринга, который используется для рисования всех «ячеек» уникального компонента, отображающего всех людей. Вам действительно нужно 3000 человек, отображаемых одновременно. Не могли бы вы просто показать сотни людей и использовать форму поиска или нумерацию страниц?
  • 1
    @JBNizet делает важный момент, как предлагается здесь .
Показать ещё 5 комментариев
Теги:
multithreading
swing
swingworker

1 ответ

0

Политика Swing Threading:

В общем, Swing не является потокобезопасным. Все компоненты Swing и связанные классы, если не указано иное, должны быть доступны в потоке диспетчеризации событий. Типичные приложения Swing обрабатывают в ответ на событие, созданное с помощью жестов пользователя. Например, нажатие на JButton уведомляет все ActionListeners, добавленные в JButton. Поскольку все события, созданные с помощью жестов пользователя, отправляются в поток диспетчеризации событий, большинство разработчиков не подвержено влиянию ограничения.

Однако, когда это имеет место, он разрабатывает и демонстрирует приложение Swing. Вызовы основного метода приложения или методы в Applet не вызываются в потоке диспетчеризации событий. Таким образом, при создании и показе приложения или апплета необходимо следить за передачей управления потоку отправки событий. Предпочтительным способом передачи управления и начала работы с Swing является использование invokeLater. Метод invokeLater рассылает Runnable для обработки в потоке диспетчеризации событий.

Вы не должны создавать компоненты Swing вне EventDispatchThread, потому что обновление модели компонента генерирует события, более подробно здесь.

Чтобы углубить этот ответ, может быть просветляющим.

Как упоминалось в комментарии к вашему вопросу "paging", и, возможно, "загрузочная панель" может решить вашу проблему.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню