首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaFX WebEngine JavaScript上线

JavaFX WebEngine JavaScript上线
EN

Stack Overflow用户
提问于 2017-11-11 01:43:58
回答 1查看 465关注 0票数 1

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

代码语言:javascript
复制
Hello World

然而,在java Windows 10 pro x64 jre 1.8.0_152中,似乎存在某种断开,因为单击该按钮后,它将不会输出任何用于控制台的内容。

为什么在最新版本的java (当时是152)上,我的代码给出了不可预测和通常不想要的结果。我尝试给出最低限度的代码来创建下面的场景。

代码语言:javascript
复制
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");
    }
}}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-11 03:06:14

new Bridge()传递给setMember方法。因为没有变量保存Bridge实例,所以它在按下按钮之前就会被垃圾收集。

来自WebEngine文档

注意,在上面的示例中,应用程序保存对JavaApplication实例的引用。这是从JavaScript执行所需方法的回调所必需的。 在下面的示例中,应用程序不包含对Java对象的引用: JSObject window = (JSObject) webEngine.executeScript("window"); window.setMember("app", new JavaApplication()); 在这种情况下,由于属性值是一个本地对象"new JavaApplication()",因此该值可能在下一个GC循环中被垃圾收集。 当用户单击链接时,它并不保证执行回调方法exit

将Bridge对象保存在字段中,以防止垃圾收集:

代码语言:javascript
复制
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版本可以自由地更改垃圾收集的时间和行为。你很幸运,但在以后的版本中,你的运气就完了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47233516

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档