JavaFX SwingWorker 等效?

JavaFX SwingWorker Equivalent?

是否有 JavaFX 等同于 Java SwingWorker 类?

我知道 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).

永远不要使用 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 如下:

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 

解释:

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

如果这还不够,您可以随时使用 Platform.runLater() to schedule GUI updates. If you are doing too many GUI updates and the GUI Thread is being slowed down, you can use the following idiom: Throttling javafx gui updates

除了只能传递字符串的 updateMessage 方法之外,还有 updateValue 方法可以传递整个对象,所以我相信您可以以类似的方式使用它。 Task 文档的 "A Task Which Returns Partial Results" 部分描述了这种方法。另一种方法是其他答案中也提到的 Platform.runLater() 方法。

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

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