Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/474.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX的Javascript桥/上调用(通过JSObject.setMember()方法)在分发时中断_Javascript_Javafx_Jar_Bridge_Jsobject - Fatal编程技术网

JavaFX的Javascript桥/上调用(通过JSObject.setMember()方法)在分发时中断

JavaFX的Javascript桥/上调用(通过JSObject.setMember()方法)在分发时中断,javascript,javafx,jar,bridge,jsobject,Javascript,Javafx,Jar,Bridge,Jsobject,问题 我花了几个小时试图确定我的分布式代码失败的原因,但在使用IDE(NetBeans)进行调试时,我的源代码没有问题。我已经找到了一个解决方案,并且正在发帖帮助可能有类似问题的其他人。 顺便说一句:我是一名自学成才的程序员,可能缺少一些基本概念——请随意教育我 背景信息 使用JavaFX应用程序中的WebView控件,我从html文件加载网页。我想使用JavaScript来处理HTML方面的事情,但我还需要在Java和JavaScript之间自由地传递信息(双向)。使用WebEngine.ex

问题

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

背景信息

使用JavaFX应用程序中的WebView控件,我从html文件加载网页。我想使用JavaScript来处理HTML方面的事情,但我还需要在Java和JavaScript之间自由地传递信息(双向)。使用WebEngine.executeScript()方法进行Java启动的传输,并在Java中使用JSObject.setMember()为JavaScript设置一种向Java启动信息传输的方法,效果非常好

设置链接(这种方式稍后中断):

上面的代码在分发它并尝试运行JAR文件之前将非常有效。经过数小时的搜索和测试,我终于将问题缩小到JavaLink对象本身(我最终了解到可以在JavaScript中使用try-catch块,这使我能够捕捉到错误:“TypeError:showMsg不是函数…”)。

解决方案

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

JavaLink jl;

...

    jl = new JavaLink();

    //replace anonymous instantiation of JavaLink with global variable
    jsObj.setMember("javaLink", jl); 
为什么


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

只是为了证明@DatuPuti的答案中假设的假设似乎是正确的。这里有一个快速测试。按下HTML按钮可增加HTML页面中的计数器,还可输出到系统控制台。按下“GC”按钮强制垃圾收集后,系统控制台的更新停止:

import javafx.application.Application;
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.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

public class WebViewCallbackGCTest extends Application {

    private final String HTML = 
              "<html>"
            + "  <head>"
            + "    <script>"
            + "    var count = 0 ;"
            + "    function doCallback() {"
            + "      count++ ;"
            + "      javaLink.showMsg('Hello world '+count);"
            + "      document.getElementById('test').innerHTML='test '+count;"
            + "    }"
            + "    </script>"
            + "  </head>"
            + "  <body>"
            + "    <div>"
            + "      <button onclick='doCallback()'>Call Java</button>"
            + "    </div>"
            + "    <div id='test'></div>"
            + "  </body>"
            + "</html>" ;

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

        JSObject js = (JSObject) webView.getEngine().executeScript("window");
        js.setMember("javaLink", new JavaLink());

        Button gc = new Button("GC");
        gc.setOnAction(e -> System.gc());

        BorderPane root = new BorderPane(webView);
        BorderPane.setAlignment(gc, Pos.CENTER);
        BorderPane.setMargin(gc, new Insets(5));
        root.setBottom(gc);
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }

    public static class JavaLink {
        public void showMsg(String msg) {
            System.out.println(msg);
        }
    }

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

js.setMember("javaLink", new JavaLink());


问题已经解决,在调用
System.gc()后,更新会继续出现在控制台中

来自@DatuPuti的解决方案运行良好,但部分有效。在我的例子中,JavaLink类中有多个嵌套类。在执行@DatuPuti公开所有嵌套类链接中断的操作之前,在应用公开的解决方案之后,只有被调用的类是保持链接的类,其余所有类仍在中断。这是我的JavaLink类的模型:

public class JavaLink{

    public NestedClass1 ClassName1;
    public NestedClass2 ClassName2;

    //Constructor
    public JavaLink(){
        ClassName1 = new NestedClass1();
        ClassName2 = new NestedClass2();
    }

    //Nested classes being called from Javascript
    public class NestedClass1(){}
    public class NestedClass2(){}

}
链接的创建方式如下:

JavaLink javaLink;
...

    javaLink = new JavaLink();
    jsObject.setMember("JavaLink", javaLink);
JavaLink.ClassName1.method();
JavaLink.ClassName2.method();
然后,我从Javascript调用类方法,如下所示:

JavaLink javaLink;
...

    javaLink = new JavaLink();
    jsObject.setMember("JavaLink", javaLink);
JavaLink.ClassName1.method();
JavaLink.ClassName2.method();
问题来了:当崩溃发生时,调用
ClassName1
方法,
ClassName2
取消链接,并且不再使用Javascript。如果在调用
ClassName2
方法时发生崩溃,也会发生同样的情况

对我有效的解决方案(除了暴露的解决方案):

除了在更高的范围内声明
JavaLink
,声明所有嵌套类将使它们保留链接。例如(保留与示例相同的引用 班级模式):

最后,为了从Javascript中的嵌套类调用方法,需要重新分配对象,如下所示(Javascript):


我希望这能帮助人们面对同样的问题。我将Java JDK 1.8与IntelliJIDEA结合使用。

听起来是可行的。您可以通过调用
System.gc()
(例如,在某个事件处理程序中,您可以控制何时调用它)在netbeans中运行原始版本来测试此假设。如果您的猜测是正确的,调用
System.gc()
将导致它立即停止工作。我可以确认这一点,谢谢您的分享!然而,JRE的JavaFX行为在u91和u151之间发生了变化。即使在官方教程中,仍然有“老”方法:kotlin/tornadoFX也有同样的问题。使用类成员而不是匿名对象解决了这个问题。谢谢分享。
JavaLink.ClassName1.method();
JavaLink.ClassName2.method();
JavaLink javaLink;
JavaLink.NestedClass1 nestedClass1;
JavaLink.NestedClass2 nestedClass2;

    javaLink = new JavaLink();
    nestedClass1 = javaLink.new NestedClass1();
    nestedClass2 = javaLink.new NestedClass2();

    //Creating an Object array to store classes instances
    Object[] javaLinkClasses = new Object[2];
    javaLinkClasses[0] = nestedClass1;
    javaLinkClasses[1] = nestedClass2;
    jsObject.setMember("JavaLink", javaLinkClasses); //Setting member as an array
JavaLink.NestedClass1 = JavaLink[0];
JavaLink.NestedClass2 = JavaLink[1];

//Now we are able to call again methods from nested classes without them unlinking
JavaLink.NestedClass1.method();