34

我有一个 javafx 应用程序和一个通过 实现的工作线程,javafx.concurrent.Task它执行一个漫长的过程,即压缩和上传一组文件。
我已通过 将任务进度连接到进度条progressProperty
除此之外,我希望将有关正在处理的项目的详细状态报告到 ui 中。也就是说,正在处理的文件的名称及其大小以及单个文件进程可能出现的任何错误。
无法从工作线程中使用这些信息更新 UI,最多我可以将其添加到同步集合中。
但随后我需要一些事件来通知 UI 新数据可用。
javafx 对这个问题有特定的支持吗?

更新,更好的配方

我没有像 Platform.runLater 那样设计一个特别的跨线程机制,而是试图让每个属性都可以从其他线程中被监听。就像 Task 提供的 runningProperty 和 stateProperty

4

2 回答 2

39

我遇到了类似的问题,据我所知,您必须自己处理错误。我的解决方案是通过方法调用更新 UI:

就像是:

  try
  {
    //blah...
  }
  catch (Exception e)
  {
    reportAndLogException(e);
  }
  ...
  public void reportAndLogException(final Throwable t)
  {
    Platform.runLater(new Runnable() {
      @Override public void run() {
        //Update UI here     
      }
    });
  }

本质上,我只是手动将其移回 UI 线程进行更新(就像我在几乎任何其他框架中所做的那样)。

于 2012-07-27T15:37:22.627 回答
7

这个答案使用与丹尼尔的答案相同的概念。

随附的是来自Task javadoc的 Partial Result 示例的副本(针对当前嵌入在 Java 8 javadoc 中的语法错误进行了修复,并添加了更具体的 Generic 类型)。您可以使用它的修改。

将您的异常放在 partialResults 集合中。对于您的情况,您不需要从任务返回异常列表,而是可以将它们放在一些显示异常的 UI 控件中(例如ListView带有CellFactory异常显示的 a)。请注意,partialResults 集合不需要同步,因为它总是在 JavaFX UI 线程上更新和访问(更新是通过Platform.runLater()类似于 Daniel 解决方案的调用发生的)。

public class PartialResultsTask extends Task<ObservableList<Rectangle>> {
    private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults =
            new ReadOnlyObjectWrapper<>(
                    this, 
                    "partialResults",
                    FXCollections.observableArrayList(
                            new ArrayList<>()
                    )
            );

    public final ObservableList<Rectangle> getPartialResults() {
        return partialResults.get();
    }

    public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty() {
        return partialResults.getReadOnlyProperty();
    }

    @Override
    protected ObservableList<Rectangle> call() throws Exception {
        updateMessage("Creating Rectangles...");
        for (int i = 0; i < 100; i++) {
            if (isCancelled()) break;
            final Rectangle r = new Rectangle(10, 10);
            r.setX(10 * i);
            Platform.runLater(() -> partialResults.get().add(r));
            updateProgress(i, 100);
        }
        return partialResults.get();
    }
}

更新它的可观察属性时,任务首先检查更新是否发生在 FX 应用程序线程上。如果是,它会立即更新。如果不是,则它将更新包装在Platform.runLater()调用中。请参阅任务源代码以了解这是如何完成的。

也许可以定义一组通用的并发感知属性,但 JavaFX 并没有在其核心提供这样的设施。确实,没必要。除了 javafx.concurrent 包之外,JavaFX 是一个单线程 UI 框架。

于 2012-07-27T17:32:06.093 回答