JREバージョン1.8.0_66から1.8.0_111への移行後、JavaScriptからJavaFXへのupcallの作成に問題が発生しました。JavaScriptからJavaFXへのバックグラウンドスレッドのブレーキ
短いストーリー:実行中のバックグラウンドスレッドがあるのに、WebView/WebEngineはJS-to-Java呼び出しを拒否します。
WebViewを使用して、ドメインデータモデル(DM)から生成されたHTMLコンテンツをレンダリングします。 jsBridge
はコントローラ
public class JSBridge {
public void jsHandleQuery(String headWord) {
log("jsBridge: jsHandleQuery: requested %s", headWord);
handleQuery(headWord);
}
public void jsTest() {
log("jsBridge: jsTest: test succeeded ");
}
}
の内部Javaクラスです
function explainHeadWord(hwElement) {
jsBridge.jsHandleQuery(hwElement.innerHTML);
}
function testBridge() {
jsBridge.jsTest();
}
:
<a href='#' onclick='explainHeadWord(this)'>some_word</a>
JSの部分は次のようになります。次のようにコンテンツがそれに割り当てられたハンドラを持つ要素が含まれています
を以下のように注入する:
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以外に、私はMap<String, Collection<String>>
はDMから構築されたクロスリファレンスのインデックス、およびバックグラウンドで各時間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の中のアンカーをクリックすると、期待されたhandleQuery(headWord)
に最終的にJS-コールとしましたコントローラで実装されたメソッド呼び出し。しかし、JREをバージョン1.8.0_111に移行した後、アンカークリックに応答するためにWebViewが停止しました。
私はログを調査して、jsBridge
の注入が成功したことと、window.setMember()
のコードにコメントされたテストスクリプトを実行していることが判明しました。 <a>
要素をクリックすると何も表示されませんでした。
<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のコンテンツが<a>
要素をクリックが開始リロードされました:しかし、テストスクリプトを実行せずに(コメント)レコードがログに登場していました再度応答する - jsBridge.jsHandleQuery
が実行されました。 インデックス作成スレッドは、DMをトラバースして収集したgetIndex()
メソッドを実行して、DMからデータをMap
に返します。 FXアプリケーションスレッドとのやりとりや、WebViewはインデックスに依存しています。バックグラウンドスレッドでfullSearchIndex = getMockIndex();
private Map<String, Collection<String>> getMockIndex() {
try {
Thread.sleep(20000);
} catch (InterruptedException e) { }
return Collections.emptyMap();
}
を代入すると<a>
の動作を変更しません。
javafx.concurrent.Service
を利用してバックグラウンドスレッドをFXスタイルにリファクタリングすることでしたが、結果は同じです。
私は何が間違っているのか、この問題に取り組む方法を指摘していただきありがとうございます。