javafx, update ui from another thread

2019-01-07 17:46发布

I have a javafx application, and a worker thread, implemented via javafx.concurrent.Task, that performs a long process, that is zipping and uploading a set of files.
I've connected the task progress to a progress bar via progressProperty.
In addition to this i want a detailed state about the item being processed to be reported into the ui. That is, the name of the file being processed along with its size and any error that may arise from the single file process.
Updating the UI with these information cannot be done from the worker thread, at the most i can add it to a synchronized collection.
But then i need some event to inform the UI that new data is available.
Does javafx have some specific support for this issue?

update, better formulation

Instead of designing an ad hoc cross-thread mechanism as Platform.runLater, i'm trying to allow each property to be listened from other threads. Just like runningProperty and stateProperty provided by Task

2条回答
你好瞎i
2楼-- · 2019-01-07 18:10

I'm running into a similar issue, as far as I can tell you have to deal with the error handling yourself. My solution is to update the UI via a method call:

Something like:

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

Essentially I am just manually moving it back to the UI Thread for an update (as I would do in pretty much any other framework).

查看更多
等我变得足够好
3楼-- · 2019-01-07 18:14

This answer uses the same concept as Daniel's answer.

Enclosed is a copy of the Partial Result sample from the Task javadoc (fixed for syntax errors currently embedded in the Java 8 javadoc and to add more specific Generic types). You can use a modification of that.

Place your exceptions in the partialResults collection. For your case, you don't need to return the list of exceptions from the Task, but can instead place them in some UI control which displays the exceptions (like a ListView with a CellFactory for exception display). Note that the partialResults collection did not need to be synchronized because it is always updated and accessed on the JavaFX UI thread (the update is happening via a Platform.runLater() call similar to Daniel's solution).

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();
    }
}

When updating it's observable properties Task first checks if the update is occurring on the FX Application thread. If it is, it does an immediate update. If it is not, then it wraps the update in a Platform.runLater() call. See the Task source code to understand how this is done.

Perhaps it would be possible to define a set of generic concurrent aware properties, but JavaFX does not provide such facilities at it's core. Indeed, it doesn't need to. With the exception of the javafx.concurrent package, JavaFX is a single threaded UI framework.

查看更多
登录 后发表回答