2017-01-27 8 views
6

के बाद विफल रहा है मैं वर्तमान में जावाएफएक्स आधारित एप्लिकेशन पर काम कर रहा हूं, जहां उपयोगकर्ता दुनिया के मानचित्र पर चिह्नित स्थानों के साथ बातचीत कर सकते हैं। ऐसा करने के लिए, मैं http://captaincasa.blogspot.de/2014/01/javafx-and-osm-openstreetmap.html ([1]) में वर्णित एक दृष्टिकोण के समान दृष्टिकोण का उपयोग कर रहा हूं।जावास्क्रिप्ट से JavaFx WebView कॉलबैक कचरा संग्रह

हालांकि, मुझे वेब आंगन के सेटमेम्बर() विधि का उपयोग करके एम्बेडेड HTML-पृष्ठ पर इंजेक्शन वाले जावास्क्रिप्ट कॉलबैक चर से संबंधित हार्ड-टू-डीबग समस्या का सामना करना पड़ रहा है (आधिकारिक ट्यूटोरियल के लिए https://docs.oracle.com/javase/8/javafx/embedded-browser-tutorial/js-javafx.htm ([2]) भी देखें) ।

थोड़ी देर के लिए प्रोग्राम चलाते समय, कॉलबैक चर अपने राज्य को अप्रत्याशित रूप से खो रहा है! इस व्यवहार को प्रदर्शित करने के लिए, मैंने एक न्यूनतम काम/असफल उदाहरण विकसित किया। मैं विंडोज 10 मशीन पर jdk1.8.0_121 64-बिट का उपयोग कर रहा हूं।

<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> 
<!-- use for in-browser debugging --> 
<!-- <script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> --> 
<script type="text/javascript"> 
    var javaApp = null; 

    function javaCallback(data) {   
     try { 
      alert("javaApp=" + javaApp + "(type=" + typeof javaApp + "), data=" + data); 
      javaApp.callback(data); 
     } catch (e) { 
      alert("caugt exception: " + e); 
     } 
    } 
</script> 
</head> 
<body> 
    <button onclick="javaCallback('Test')">Send data to Java</button> 
    <button onclick="setInterval(function(){ javaCallback('Test'); }, 1000)">Send data to Java in endless loop</button> 
</body> 
</html> 

कॉलबैक चर javaApp की स्थिति पर क्लिक करके देखा जा सकता है:

import java.text.DateFormat; 
import java.text.SimpleDateFormat; 
import java.util.Date; 

import javafx.application.Application; 
import javafx.concurrent.Worker.State; 
import javafx.scene.Scene; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.web.WebEngine; 
import javafx.scene.web.WebView; 
import javafx.stage.Stage; 
import netscape.javascript.JSObject; 

public class WebViewJsCallbackTest extends Application { 

    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 

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

    public class JavaScriptBridge { 
     public void callback(String data) { 
      System.out.println("callback retrieved: " + data); 
     } 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     WebView webView = new WebView(); 
     primaryStage.setScene(new Scene(new AnchorPane(webView))); 
     primaryStage.show(); 

     final WebEngine webEngine = webView.getEngine(); 
     webEngine.load(getClass().getClassLoader().getResource("page.html").toExternalForm()); 

     webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> { 
      if (newValue == State.SUCCEEDED) { 
       JSObject window = (JSObject) webEngine.executeScript("window"); 
       window.setMember("javaApp", new JavaScriptBridge()); 
      } 
     }); 

     webEngine.setOnAlert(event -> { 
      System.out.println(DATE_FORMAT.format(new Date()) + " alerted: " + event.getData()); 
     }); 
    } 

} 

HTML फ़ाइल "page.html" इस प्रकार दिखता है:

JavaFX अनुप्रयोग के रूप में निम्नानुसार लग रहा है "Send data to Java in endless loop" बटन। यह javaApp.callback के माध्यम से कॉलबैक विधि को चलाने की कोशिश करेगा, जो जावा ऐप में कुछ लॉगिंग संदेश उत्पन्न करता है। अलर्ट का उपयोग चीजों को वापस करने के लिए एक अतिरिक्त संचार चैनल के रूप में किया जाता है (हमेशा काम करता है और वर्तमान में काम के आसपास के रूप में उपयोग किया जाता है, लेकिन ऐसा नहीं है कि चीजें कैसे हैं ...)।

सब कुछ कार्य के रूप में माना जाता, हर बार निम्नलिखित लाइनों के लिए समान प्रवेश करने मुद्रित तो है किया जाना चाहिए:

callback retrieved: Test 
2017/01/27 21:26:11 alerted: [email protected]c693(type=object), data=Test 

हालांकि, कुछ समय के बाद (कुछ भी 2-7 मिनट से), कोई और अधिक कॉलबैक प्राप्त किए गए हैं, लेकिन निम्न पंक्ति की तरह केवल loggings मुद्रित कर रहे हैं:

2017/01/27 21:32:01 alerted: javaApp=undefined(type=object), data=Test

चर मुद्रण अब जावा उदाहरण पथ के बजाय 'undefined' देता है। एक अजीब अवलोकन यह है कि javaApp की स्थिति वास्तव में "अपरिभाषित" नहीं है। typeof का उपयोग object, javaApp === undefinedfalse का मूल्यांकन करता है। यह इस तथ्य के अनुसार है कि कॉलबैक-कॉल अपवाद नहीं फेंकता है (अन्यथा, "caugt exception: " से शुरू होने वाली चेतावनी मुद्रित की जाएगी)।

जावा विजुअलVM का उपयोग करके पता चला कि विफलता का समय कचरा कलेक्टर सक्रिय होने के समय के साथ मेल खाता है। यह हीप मेमोरी खपत को देखकर देखा जा सकता है, जो लगभग से गिरता है। जीसी के कारण 60 एमबी से 16 एमबी।

वहां क्या चल रहा है? क्या आपको कोई विचार है कि मैं इस मुद्दे को और कैसे डीबग कर सकता हूं? मुझे कोई संबंधित पता बग नहीं मिला ...

आपकी सलाह के लिए बहुत बहुत धन्यवाद!

पीएस: जावास्क्रिप्ट कोड को पत्रक (सीएफ [1]) के माध्यम से एक विश्व मानचित्र प्रदर्शित करने के लिए समस्या को बहुत तेज़ी से पुन: उत्पन्न किया गया था। मानचित्र को लोड या स्थानांतरित करने से ज्यादातर समय जीसी ने अपना काम किया। इस मूल मुद्दे को डीबग करते समय, मैंने यहां प्रस्तुत किए गए न्यूनतम उदाहरण में समस्या का पता लगाया।

+0

मुझे jdk 1.8.0_121 के साथ एक ही समस्या थी। तब मुझे एहसास हुआ कि यह एक और पीसी के साथ मिलकर काम करता है जो jdk 1.8.0_60 चला रहा है। 1.8.0_60 पर स्विच किया गया और समस्या हल हो गई। –

+0

@AliAyadJalil: पुराने संस्करण में वापस गिरना हमेशा वांछनीय या यहां तक ​​कि एक संभावना नहीं है। : -/ –

उत्तर

7

मैंने जावा में एक उदाहरण चर bridge बनाकर समस्या हल की है जिसमें JavaScriptBridge उदाहरण setMember() के माध्यम से जावास्क्रिप्ट को भेजा गया है। इस तरह, उदाहरण के गर्गबेस संग्रह को रोका गया है।

प्रासंगिक कोड का टुकड़ा:

public class JavaScriptBridge { 
    public void callback(String data) { 
     System.out.println("callback retrieved: " + data); 
    } 
} 

private JavaScriptBridge bridge; 

@Override 
public void start(Stage primaryStage) throws Exception { 
    WebView webView = new WebView(); 
    primaryStage.setScene(new Scene(new AnchorPane(webView))); 
    primaryStage.show(); 

    final WebEngine webEngine = webView.getEngine(); 
    webEngine.load(getClass().getClassLoader().getResource("page.html").toExternalForm()); 

    bridge = new JavaScriptBridge(); 
    webEngine.getLoadWorker().stateProperty().addListener((observableValue, oldValue, newValue) -> { 
     if (newValue == State.SUCCEEDED) { 
      JSObject window = (JSObject) webEngine.executeScript("window"); 
      window.setMember("javaApp", bridge); 
     } 
    }); 

    webEngine.setOnAlert(event -> { 
     System.out.println(DATE_FORMAT.format(new Date()) + " alerted: " + event.getData()); 
    }); 
} 

कोड अब (यह भी पत्रक के साथ) का सुचारू रूप से काम करता है हालांकि, मैं अभी भी इस अप्रत्याशित व्यवहार की चिढ़ हूँ ...

यह एक तरह लगता है के बाद से काम-आसपास, मैं इसे अब तक सही उत्तर के रूप में स्वीकार नहीं करूंगा जब तक कि कोई यह समझा न सके कि इस व्यवहार की अपेक्षा क्यों की जानी चाहिए/सही है।

+0

देखें: https://bugs.openjdk.java.net/browse/JDK-8154127 –

+0

धन्यवाद आपका कोड मेरा दिन बचाता है, जवाब – Dinesh

+0

ओएमजी स्वीकार किया जाना चाहिए। क्या एक भयानक Heisenbug। इस उत्तर के लिए धन्यवाद दस लाख। मैंने समस्या के स्रोत की तलाश में दिन बिताए हैं। –

संबंधित मुद्दे