javafx,从另一个线程更新ui

Ago*_*noX 30 java exception-handling thread-safety javafx-2

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

更新,更好的配方

我没有将特设的跨线程机制设计为Platform.runLater,而是试图允许从其他线程中侦听每个属性.就像Task提供的runningProperty和stateProperty一样

Dan*_*man 34

我遇到了类似的问题,据我所知,你必须自己处理错误处理.我的解决方案是通过方法调用更新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     
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)

基本上我只是手动将其移回UI线程进行更新(正如我在其他任何框架中所做的那样).

  • 是的,但例外是案例的例外.通常,您希望立即报告,这不是特别的,它是重新加入UI线程以进行更新的标准FX方法.我同意其余的遵循休息模式,但绝不意味着它必须.希望其他人会有一个光滑的答案(启发很好!) (2认同)

jew*_*sea 7

这个答案与Daniel的答案使用相同的概念.

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

将您的例外放在partialResults集合中.对于您的情况,您不需要从任务返回异常列表,而是可以将它们放在显示异常的某个UI控件中(例如ListView带有CellFactory异常显示的异常).请注意,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

也许可以定义一组通用的并发感知属性,但JavaFX并没有提供这样的设施.实际上,它并不需要.除了javafx.concurrent包之外,JavaFX是一个单线程UI框架.