【问题标题】:JavaFX SwingWorker Equivalent?JavaFX SwingWorker 等价物?
【发布时间】:2015-03-06 02:36:18
【问题描述】:

是否有与 Java SwingWorker 类等效的 JavaFX?

我知道 JavaFX Task 但您只能发布字符串消息或进度。我只想在 GUI 线程中调用一个方法,就像我对 SwingWorker 所做的那样(通过发布任意类型的消息)。

这是我的意思的一个例子:

class PrimeNumbersTask extends
         SwingWorker<List<Integer>, Integer> {
     PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
         //initialize
     }

      @Override
     public List<Integer> doInBackground() {
         while (! enough && ! isCancelled()) {
                 number = nextPrimeNumber();
                 publish(number);
                 setProgress(100 * numbers.size() / numbersToFind);
             }
         }
         return numbers;
     }

      @Override
     protected void process(List<Integer> chunks) {
         for (int number : chunks) {
             textArea.append(number + "\n"); // HERE: execute in GUI thread
         }
     }
 }

解决方案

非常感谢您的回答。我正在寻找的解决方案是使用Platform.runLater(Runnable guiUpdater)

【问题讨论】:

    标签: java multithreading javafx thread-safety worker


    【解决方案1】:

    我会重写你的SwingWorker 如下:

    class PrimeNumbersTask extends Task<List<Integer>> {
        PrimeNumbersTask(TextArea textArea, int numbersToFind) {
            // initialize
        }
    
        @Override
        protected List<Integer> call() throws Exception {
            while (!enough && !isCancelled()) {
                number = nextPrimeNumber();
                updateMessage(Integer.toString(number));
                updateProgress(numbers.size(), numbersToFind);
            }
            return numbers;
        }
    }
    

    用法:

    TextArea textArea = new TextArea();
    PrimeNumbersTask task = new PrimeNumbersTask(numbersToFind);
    task.messageProperty().addListener((w, o, n)->textArea.appendText(n + "\n"));
    new Thread(task).start(); // which would actually start task on a new thread 
    

    说明:

    是的,我们没有 publish() 方法,就像 JavaFX 中的 SwingWorker 那样,但在您的情况下,使用 updateMessage() 就足够了,因为我们可以为此属性注册一个侦听器并在每个消息更新的时间。

    如果这还不够,您可以随时使用Platform.runLater() 来安排 GUI 更新。如果您进行过多的 GUI 更新并且 GUI 线程被拖慢,您可以使用以下成语:Throttling javafx gui updates

    【讨论】:

    • 我已经在考虑这个解决方案,但在我看来它更像是一种解决方法(好吧,它适用于主要示例,但并非在所有情况下都适用)。 Platform.runLater() 方法正是我想要的。
    • 您刚刚创建了新的任务实例,并没有启动 PrimeNumbersTask 的任何后台工作。我想需要调用把它放在一个线程上并启动它。否则,如果只是调用 task.run() GUI 被阻止.. 我随意添加缺少的行: new Thread(task).start();让我知道这是否可以
    【解决方案2】:

    除了只能传递字符串的updateMessage 方法之外,还有可以传递整个对象的updateValue 方法,所以我相信你可以以类似的方式使用它。 Task 文档的“返回部分结果的任务”部分描述了这种方法。另一种方法是其他答案中也提到的Platform.runLater() 方法。

    请注意,这些方法之间的一个重要区别是,第一个方法是合并结果,这意味着对于多个频繁的 updateValue 调用,可能会省略一些方法,以防止 FX 线程泛滥。

    另一方面,Platform.runLater 方法将发送所有中间结果,但由于如果您有高频更新会导致 FX 线程泛滥的危险,可能需要一些额外的努力来手动避免它,例如 @eckig在他的回答中建议指向Throttling javafx gui updates

    【讨论】:

      【解决方案3】:

      永远不要使用 SwingWorker。 SwingWorker.java 源代码中的这段代码应该足以作为不使用它的参数:

      private static final int MAX_WORKER_THREADS = 10;
      

      而是让自己熟悉Executor 以及随之而来的服务。

      它与 JavaFX 无关,它只是普通的 Java。但是,您的问题与 JavaFX 有关。这是一个关于如何Update UI in JavaFX Application Thread using Platform.runLater()的示例。

      【讨论】:

      • 了解您的不喜欢,但只是想知道SwingWorker 是否实际上没有处理从非 EDT 到 EDT (process) 的块传输,比创建 Runnable 时的效率略高。时间。查看publish 的源代码,我看到AccumulativeRunnable 实例包含在包sun.swing 中。不知道这意味着什么,作为一个完整的 JavaFX 新手,我不知道我们是否会看到类似的东西......
      猜你喜欢
      • 1970-01-01
      • 2017-07-31
      • 1970-01-01
      • 2017-05-11
      • 1970-01-01
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      • 2015-10-17
      相关资源
      最近更新 更多