【问题标题】:JavaFx WebView wait for Java method to finishJavaFx WebView 等待 Java 方法完成
【发布时间】:2026-01-10 21:20:05
【问题描述】:

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

【问题讨论】:

    标签: javascript multithreading asynchronous javafx webview


    【解决方案1】:

    由于一切都在 FX 应用线程上执行,因此您调用的 Java 方法需要在后台线程上运行长时间运行的进程(否则您将导致 UI 无响应)。您可以向该方法传递一个 Javascript 函数以在完成时调用:请注意,此 javascript 函数需要在 FX 应用程序线程上调用。一种方法是将调用封装在 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 方面的专家 Java 通信,但这对我来说似乎没问题。)

    【讨论】: