Javascript桥接/上传到JavaFX(通过JSObject.setMember()方法)在分发时中断

Dat*_*uti 4 javascript bridge javafx jar jsobject

问题

我花了几个小时试图确定我的分布式代码失败的原因,但是在使用IDE(NetBeans)调试时我的源代码没有问题.我找到了一个解决方案,并发帖帮助其他可能有类似问题的人.顺便说一句:我是一个自学成才的程序员,可能会缺少一些基本概念 - 随时教育我.

背景资料

在JavaFX应用程序中使用WebView控件我从html文件加载网页.我想使用JavaScript来处理HTML方面,但我还需要在Java和JavaScript之间自由传递信息(两个方向).非常适合使用WebEngine.executeScript()方法进行Java启动的传输,并使用Java中的JSObject.setMember()为JavaScript启动向Java传输信息的方法.

设置链接(这种方式稍后会破坏):

/*Simple example class that gives method for 
JavaScript to send text to Java debugger console*/
public static class JavaLink {
    public void showMsg(String msg) {
        System.out.println(msg);
    }
}

...

/*This can be added in the initialize() method of  
the FXML controller with a reference to the WebEngine*/
public void initialize(URL url, ResourceBundle rb) {
    webE = webView.getEngine();

    //Retrieve a reference to the JavaScript window object
    JSObject jsObj = (JSObject)webE.executeScript("window");
    jsObj.setMember("javaLink", new JavaLink());
    /*Now in our JavaScript code we can type javaLink.showMsg("Hello!");
    which will send 'Hello!' to the debugger console*/
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将很有用,直到分发它并尝试运行JAR文件.经过几个小时的搜索和测试不同的调整,我最终将问题缩小到JavaLink对象本身(我最终了解到你可以在JavaScript中使用try-catch块,这使我能够捕获错误:" TypeError:showMsg不是一个函数. .. ").

Dat*_*uti 6

解决方案

我发现声明一个全局变量来保存JavaLink类的实例并将其作为参数传递到setMember()方法中进行修复,以便应用程序现在既可以在IDE中运行,也可以在独立的JAR中运行:

JavaLink jl;

...

    jl = new JavaLink();

    //replace anonymous instantiation of JavaLink with global variable
    jsObj.setMember("javaLink", jl); 
Run Code Online (Sandbox Code Playgroud)

为什么!?

我猜这与垃圾收集有关,除非你通过声明一个全局变量来强制它,否则JVM不会保留对JavaLink的引用.还有其他想法吗?