从JavaScript到JavaFX的后台线程调用
在将JRE版本1.8.0_66迁移到1.8.0_111之后,我遇到了一个从JavaScript到JavaFX的升级调用问题 长话短说:虽然有一个正在运行的后台线程,但WebView/WebEngine拒绝进行JS到Java的调用 我使用WebView呈现从域数据模型(DM)生成的HTML内容。内容包含指定了处理程序的元素,如下所示:从JavaScript到JavaFX的后台线程调用,javascript,multithreading,javafx,webview,Javascript,Multithreading,Javafx,Webview,在将JRE版本1.8.0_66迁移到1.8.0_111之后,我遇到了一个从JavaScript到JavaFX的升级调用问题 长话短说:虽然有一个正在运行的后台线程,但WebView/WebEngine拒绝进行JS到Java的调用 我使用WebView呈现从域数据模型(DM)生成的HTML内容。内容包含指定了处理程序的元素,如下所示: JS部分看起来像: function explainHeadWord(hw元素){ jsBridge.jsHandleQuery(hwmelement.inn
JS部分看起来像:
function explainHeadWord(hw元素){
jsBridge.jsHandleQuery(hwmelement.innerHTML);
}
函数testBridge(){
jsBridge.jsTest();
}
其中jsBridge
是控制器的内部Java类
公共类JSBridge{
public void jsHandleQuery(字符串标题词){
日志(“jsBridge:jsHandleQuery:requested%s”,headWord);
handleQuery(headWord);
}
公共测试{
日志(“jsBridge:jsTest:test successed”);
}
}
其注入方式如下:
engine.getLoadWorker().stateProperty().addListener((可观察、旧值、新值)->{
if(newValue==Worker.State.successed){
engine.setJavaScriptEnabled(true);
JSObject window=(JSObject)engine.executeScript(“window”);
setMember(“jsBridge”,newjsbridge());
//executeScript(“jsTest()”);
//executeScript(“explainHeadWord(document.getElementsByTagName('a')[0])”;
//executeScript(“jsBridge.jsHandleQuery(document.getElementsByTagName('a')[0])”;
}
除了主DM之外,我还有一个交叉引用索引,它是从DM构建的Map
,每次DM发生变化时,都会在后台重建该索引。第一种方法(在版本1.8.0_66上运行良好)基于ExecutorService:
private ExecutorService executor=Executors.newCachedThreadPool();
私有未来索引器=executor.submit(()->false);
...
私有void重建索引(){
执行人提交(()->{
索引器。取消(true);
索引器=执行器。提交(()->{
fullSearchIndex=getIndex();
如果(isIndexingAborted())返回false;
返回true;
});
试一试{
if(indexer.get()){
日志(“重置索引:完成”);
updateTableView();
}
}捕捉(中断异常e){
...
}
});
}
正如所料,在WebView中单击锚导致JS调用jsBridge.jsHandleQuery(hwElement.innerHTML)
,最终在Controller中实现handleQuery(headWord)
方法调用。但在将JRE迁移到1.8.0版之后,WebView停止响应锚单击
我调查了日志,发现注入jsBridge
是成功的,并且执行了窗口下面代码行中注释的测试脚本。setMember()
。单击
元素不会导致任何结果。但是如果不运行测试脚本(注释),日志中会出现以下记录:
2017-01-09T02:00:47
1483920047169
160
com.sun.webkit.WebPage
好的
com.sun.webkit.WebPage
fwkAddMessageToConsole
11
fwkAddMessageToConsole():message=TypeError:jsBridge.jsHandleQuery不是函数。(在'jsBridge.jsHandleQuery(hwmelement.innerHTML)'中,'jsBridge.jsHandleQuery'未定义),lineNumber=26,sourceId=jar:file:/…/jar.jar!/view.js
片刻之后,后台(索引)线程完成,WebView中的内容被重新加载,单击
元素再次开始响应-jsBridge.jsHandleQuery
被执行。
索引线程执行getIndex()
方法,该方法遍历DM并返回从DM收集到的Map
数据。与FX应用程序线程的任何交互都不存在,WebView也不依赖于索引。替换fullSearchIndex=getMockIndex();
私有映射getMockIndex(){
试试{
睡眠(20000);
}捕获(中断异常e){}
return Collections.emptyMap();
}
在后台,线程不会改变
的行为
下一步是利用
javafx.concurrent.Service
但结果是一样的
感谢您指出我做错了什么以及如何解决这个问题。尝试在监听器之外实例化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)