JavaFx WebView等待Java方法完成

时间:2017-03-02 00:58:06

标签: javascript multithreading asynchronous javafx webview

我在JavaFx WebView中从JavaScript调用Java方法。 Java方法可以完成一些工作,即不会立即返回。等待该方法从JavaScript完成的自然方式是什么?

1 个答案:

答案 0 :(得分:1)

由于所有内容都在FX Application Thread上执行,因此您调用的Java方法需要在后台线程上运行长时间运行的进程(否则您将使UI无响应)。您可以将方法传递给Javascript函数,以便在完成时调用:请注意,需要在FX Application Thread上调用此javascript函数。一种方法是将呼叫包裹在Platform.runLater()中,但使用Task会使事情变得更清晰。

这是一个SSCCE:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

public class WebViewCallbackTest extends Application {

    private static final String HTML = 
              "<html>"
            + "  <head>"
            + "    <script>"
            + ""
            + "      function doCall() {"
            + "         javaApp.doLongRunningCall('updateResults');"
            + "      }"
            + ""
            + "      function updateResults(results) {"
            + "         document.getElementById('results').innerHTML = results ;"
            + "      }"
            + ""
            + "    </script>"
            + "  </head>"
            + "  <body>"
            + "    <div>"
            + "      Result of call:"
            + "    </div>"
            + "    <div id='results'></div>"
            + "  </body>"
            + "</html>";

    private Button button;

    private JSObject window;

    @Override
    public void start(Stage primaryStage) {
        WebView webView = new WebView();
        webView.getEngine().loadContent(HTML);

        BorderPane root = new BorderPane(webView);

        window = (JSObject) webView.getEngine().executeScript("window");
        window.setMember("javaApp", this);


        button = new Button("Run process");
        button.setOnAction(e -> webView.getEngine().executeScript("doCall()"));

        HBox controls = new HBox(button);
        controls.setAlignment(Pos.CENTER);
        controls.setPadding(new Insets(5));
        root.setBottom(controls);

        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void doLongRunningCall(String callback) {
        Task<String> task = new Task<String>() {
            @Override
            public String call() throws InterruptedException {
                Thread.sleep(2000);
                return "The answer is 42";
            }
        };

        task.setOnSucceeded(e -> 
            window.call(callback, task.getValue()));
        task.setOnFailed(e -> 
            window.call(callback, "An error occurred"));

        button.disableProperty().bind(task.runningProperty());

        new Thread(task).start();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

(可能有一种比这更简单的方法:我不是Webview Javascript&lt; - &gt; Java通信的专家,但这对我来说似乎没问题。)

相关问题