Javafx Updating UI from a Thread without direct calling Platform.runLater

﹥>﹥吖頭↗ 提交于 2019-12-19 08:33:28

问题


Nowadays some says it is not suitable to use Platform.runLater() for updating the UI from a non-JavaFX Thread and Oracle site introduce a way with bindings for progress bar updating. Here I want to update a Label, so coded it like this:

Task task = new Task() {
    @Override
    protected Object call() throws Exception {
        int i = 0;
        while (true) {
            this.updateMessage("Count " + i);
            System.out.println(i);
            // Thread.sleep(10);
            i++;
        }
    }
};

Thread t = new Thread(task);
lbStatus.textProperty().bind(task.messageProperty());
t.start();

It works.

I want to know is it good enough or is there any other ways to consider? Thank you.


回答1:


I don't think it's quite true to say it's not "suitable" to use Platform.runLater(...) to update the UI from a background thread. There are certainly cases where that is the correct thing to do, as shown in the Task Javadocs. What the javafx.concurrent API provides is a "higher-level" interface to the functionality you commonly need when you are writing multithreaded JavaFX applications. The classes in this package are written by people with a lot of expertise in multithreaded programming, so it's likely that they have accounted for subtleties that the average programmer may not be aware of.

As an example, while it is correct that updateMessage eventually ends up calling Platform.runLater(...), the two are not completely equivalent. If you try the same thing with a naïve call to Platform.runLater(..):

// Don't do this! It will make the UI unresponsive:
Task task = new Task() {
    @Override
    protected Object call() throws Exception {
        int i = 0;
        while (true) {
            Platform.runLater(() -> lblStatus.textProperty().set("Count "+i));
            i++;
        }
        return null ;
    }
};
Thread t = new Thread(task);

your UI will become (at least partially) unresponsive. The reason is that you're scheduling so many Runnables on the FX Application thread, it doesn't have time to do its regular work (rendering UI, responding to user input, etc). The implementation of updateMessage(...) is carefully written to "throttle" the calls to Platform.runLater(...) (it basically limits them to one per frame-rendering). That code is a little tricky to implement: using the javafx.concurrent API as in your code example means you don't have to implement it yourself.

So changes to the UI must always be made on the FX Application Thread, and the way to schedule those changes is via Platform.runLater(...). In effect you either call that directly, or call code that ends up calling it. However, some of the API methods that wrap the calls to Platform.runLater(...) do so in quite sophisticated ways, and when those methods provide the functionality you need, you should probably prefer those to making the calls yourself.




回答2:


As updateMessage() on a Task finally uses Platform.runLater() to update the messageProperty, it is no alternative to a direct runLater() in your code. So the essence is:

JavaFX is not multithreaded, any Porperty binding will only work if the property is modified in the JavaFX thread, e.g. by using Platform.runLater().



来源:https://stackoverflow.com/questions/27309642/javafx-updating-ui-from-a-thread-without-direct-calling-platform-runlater

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!