【问题标题】:Background thread brakes upcall from JavaScript to JavaFX后台线程阻止了从 JavaScript 到 JavaFX 的调用
【发布时间】:2023-04-08 14:15:01
【问题描述】:

将 JRE 版本 1.8.0_66 迁移到 1.8.0_111 后,我遇到了从 JavaScript 向上调用到 JavaFX 的问题。

长话短说:当有一个正在运行的后台线程时,WebView/WebEngine 拒绝进行 JS-to-Java 调用。

我使用 WebView 呈现从域数据模型 (DM) 生成的 HTML 内容。内容包含分配有处理程序的元素,如下所示:

 <a href='#' onclick='explainHeadWord(this)'>some_word</a>

JS 部分长这样:

function explainHeadWord(hwElement) {
    jsBridge.jsHandleQuery(hwElement.innerHTML);
}

function testBridge() {
    jsBridge.jsTest();
}

其中jsBridge 是Controller 的内部Java 类

public class JSBridge {

    public void jsHandleQuery(String headWord) {
        log("jsBridge: jsHandleQuery: requested %s", headWord);
          handleQuery(headWord);
      }

      public void jsTest() {
        log("jsBridge: jsTest: test succeeded ");
      }
 }

注入如下:

engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue == Worker.State.SUCCEEDED) {
        engine.setJavaScriptEnabled(true);
          JSObject window = (JSObject) engine.executeScript("window");
          window.setMember("jsBridge", new JSBridge());
        //engine.executeScript("jsTest()");
        //engine.executeScript("explainHeadWord(document.getElementsByTagName('a')[0])");
        //engine.executeScript("jsBridge.jsHandleQuery(document.getElementsByTagName('a')[0])");
}

除了主要的 DM 之外,我还有一个交叉引用索引,它是从 DM 构建的Map&lt;String, Collection&lt;String&gt;&gt;,以及每次 DM 更改时在后台重建该索引的触发方法。第一种方法(在版本 1.8.0_66 上运行良好)基于 ExecutorService:

private ExecutorService executor = Executors.newCachedThreadPool();
private Future<Boolean> indexer = executor.submit(() -> false);

...
private void rebuildIndex() {   
    executor.submit(() -> {
        indexer.cancel(true);
        indexer = executor.submit(() -> {
              fullSearchIndex = getIndex();
              if (isIndexingAborted()) return false;
              return true;          
        });             
        try {
              if (indexer.get()) {
                  log("resetIndex: Done");
                updateTableView();
               }            
        } catch (InterruptedException e) {
        ...             
        }
      });
 } 

正如预期的那样,单击 WebView 中的锚点会导致 JS 调用 jsBridge.jsHandleQuery(hwElement.innerHTML) 并最终导致在 Controller 中实现 handleQuery(headWord) 方法调用。但是在将 JRE 迁移到 1.8.0_111 版本后,WebView 停止响应锚点点击。

我调查了日志,发现注入jsBridge 是成功的,并且执行了window.setMember() 下面代码中注释的测试脚本。单击&lt;a&gt; 元素没有任何结果。但是没有运行测试脚本(已注释),日志中出现了记录:

<record>
    <date>2017-01-09T02:00:47</date>
    <millis>1483920047169</millis>
    <sequence>160</sequence>
    <logger>com.sun.webkit.WebPage</logger>
    <level>FINE</level>
    <class>com.sun.webkit.WebPage</class>
    <method>fwkAddMessageToConsole</method>
    <thread>11</thread>
    <message>fwkAddMessageToConsole(): message = TypeError: jsBridge.jsHandleQuery is not a function. (In 'jsBridge.jsHandleQuery(hwElement.innerHTML)', 'jsBridge.jsHandleQuery' is undefined), lineNumber = 26, sourceId = jar:file:/.../jar.jar!/view.js</message>
</record>

过了一会儿,后台(索引)线程完成并重新加载了 WebView 中的内容,单击 &lt;a&gt; 元素开始再次响应 - jsBridge.jsHandleQuery 已执行。 索引线程执行getIndex() 方法,该方法遍历DM 并从DM 中返回收集到Map 的数据。与 FX 应用程序线程或 WebView 的任何交互均不依赖于 Index。代入fullSearchIndex = getMockIndex();

private Map<String, Collection<String>> getMockIndex() {
    try {           
        Thread.sleep(20000);
    } catch (InterruptedException e) { }        
    return Collections.emptyMap();
}

后台线程不会改变&lt;a&gt;的行为。

下一步是通过利用将后台线程重构为 FX 样式 javafx.concurrent.Service 但结果是一样的。

感谢您指出我做错了什么以及如何解决这个问题。

【问题讨论】:

    标签: javascript multithreading javafx webview


    【解决方案1】:

    尝试在侦听器之外实例化 Bridge,即,

    final JSBridge bridge = new JSBridge();
    engine.setJavaScriptEnabled(true);
    engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
        if (newValue == Worker.State.SUCCEEDED) {
          JSObject window = (JSObject) engine.executeScript("window");
          window.setMember("jsBridge", bridge);
        }
    });
    

    (为我从 1.8.0_91 迁移到 1.8.0_121 工作)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-12
      • 2015-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多