javascript - JavaFX WebEngine JavaScript 上行调用

标签 javascript java javafx webengine

在 java Windows 10 pro x64 jre 1.8.0_60 中,以下代码生成预期输出(单击 html 按钮后):

Hello World

但是在 java Windows 10 pro x64 jre 1.8.0_152 中似乎存在某种断开连接,因为它不会在单击按钮时向控制台输出任何内容

为什么在最新版本的 java(当时为 152)上,我的代码给出了不可预测且通常不需要的结果。我试图提供最少的代码来创建下面的场景。

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

public class Main extends Application {

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

@Override
public void start(Stage primaryStage) {
    WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();
    webEngine.setJavaScriptEnabled(true);
    webEngine.load("https://api.ipify.org/?format=json");
    webEngine.getLoadWorker().stateProperty().addListener(
            new ChangeListener<Worker.State>() {
                @Override
                public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
                    if (newState == Worker.State.SUCCEEDED) {
                        JSObject jso = (JSObject) webEngine.executeScript("window");
                        webEngine.executeScript(
                                "var button = document.createElement(\"button\");\n" +
                                        "button.innerHTML = \"Do Something\";\n" +
                                        "var body = document.getElementsByTagName(\"body\")[0];\n" +
                                        "body.appendChild(button);\n" +
                                        "button.addEventListener (\"click\", function() {java.exit();});");
                        jso.setMember("java", new Bridge());

                    }
                }
            });
    BorderPane panel = new BorderPane(browser);
    Scene scene = new Scene(panel, 700, 700);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public class Bridge {
    public void exit() {
        System.out.println("Hello World");
    }
}}

最佳答案

您正在将 new Bridge() 传递给 setMember 方法。由于没有变量保存 Bridge 实例,因此在您按下按钮之前它会被垃圾回收。

来自WebEngine documentation :

Note that in the above example, the application holds a reference to the JavaApplication instance. This is required for the callback from JavaScript to execute the desired method.

In the following example, the application does not hold a reference to the Java object:

JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApplication());

In this case, since the property value is a local object, "new JavaApplication()", the value may be garbage collected in next GC cycle.

When a user clicks the link, it does not guarantee to execute the callback method exit.

将您的 Bridge 对象保存在一个字段中以防止对其进行垃圾回收:

new ChangeListener<Worker.State>() {
    private final Bridge bridge = new Bridge();

    @Override
    public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
        if (newState == Worker.State.SUCCEEDED) {

            // ...

            jso.setMember("java", bridge);
        }
    }

为什么在早期的 Java 版本中没有出现?因为不同的 Java 版本可以自由改变垃圾收集的时间和行为。你很幸运,但在后来的版本中,你的运气用完了。

关于javascript - JavaFX WebEngine JavaScript 上行调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47233516/

相关文章:

javascript - AngularJS 添加和推送嵌套的 JSON 对象

java - 将字符串日期转换为 java.sql.Date

Java检测快速移动物体的碰撞

java - 使用 javapackager 构建 mac 安装程序时将文件夹添加到 bundle

java - javaFX中具有不同大小节点的TreeTableView

javascript - 编写一个 JavaScript 函数来反转数字

Javascript for () 循环变体

javascript - Backbone targetModel = undefined

java - 如何根据加速度估计角度以及根据 3 维角度估计加速度?

java - 通过外部切换标志来运行线程(从 GUI)