2014-05-21 29 views
9

我使用JavaFX NumberBindings來計算某些值。最初一切都按預期工作。然而,在相當少的時間之後,綁定就停止工作。我也沒有收到例外。JavaFX Bean綁定突然停止工作

我試過了幾個綁定,以及高級和低級別的方法。即使計算本身(當被重寫時)剛剛停止並且不再被調用。我也更新到最新的JDK(1.8.0_05)並重建/重新啓動了所有內容。

下面的最小工作示例說明了這個問題。它應該將System.out.println主窗口的當前寬度轉換爲STDOUT。調整窗口大小約10秒後,輸出停止。我也嘗試將結果屬性綁定到JavaFX控件,以確保Property的繼續使用,但這沒有用。我相信我在這裏錯過了Property/Bindings的一些非常基本的行爲,Google似乎完全不知道這種行爲。

import javafx.application.Application; 
import javafx.beans.binding.NumberBinding; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.scene.Scene; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class BindingsProblem extends Application { 

@Override 
public void start(Stage primaryStage) { 
    // Initialization... 
    StackPane root = new StackPane(); 
    Scene scene = new Scene(root, 300, 250); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 


    // Binding - The problem occurrs here! 
    NumberBinding currentWidthPlusTen = primaryStage.widthProperty().add(10); 
    IntegerProperty boundNumberProperty = new SimpleIntegerProperty(); 
    boundNumberProperty.bind(currentWidthPlusTen); 
    boundNumberProperty.addListener(new ChangeListener<Number>() { 

     @Override 
     public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { 
      System.out.println(newValue.toString()); 
     } 

    }); 
} 


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

} 
+0

我可以重現該問題。它看起來像一個錯誤。你在jira上搜索過嗎? – assylias

+0

我似乎無法找到現有的錯誤報告。它似乎是如此基礎的東西,很難想象它是JDK/JRE本身的錯誤。 – underkuerbis

回答

13

的結合使用WeakListener觀察的currentWidthPlusTen值。由於您不保留對boundNumberProperty的引用,因此只要start(...)方法退出,就有資格進行垃圾回收。當垃圾收集器啓動時,引用完全丟失,綁定不再起作用。

直接看到這一點,線

root.setOnMousePressed(event -> System.gc()); 

添加到start(...)方法。您可以通過單擊窗口強制偵聽器「停止工作」。

顯然,這不是你想要的:修復是在start(...)退出後保留對boundNumberProperty的引用。例如:

import javafx.application.Application; 
import javafx.beans.binding.NumberBinding; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
import javafx.scene.Scene; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class BindingsProblem extends Application { 

    IntegerProperty boundNumberProperty; 

    @Override 
    public void start(Stage primaryStage) { 
     // Initialization... 
     StackPane root = new StackPane(); 
     Scene scene = new Scene(root, 300, 250); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     // Binding - The problem occurrs here! 
     NumberBinding currentWidthPlusTen = primaryStage.widthProperty() 
       .add(10); 

     boundNumberProperty = new SimpleIntegerProperty(); 
     boundNumberProperty.bind(currentWidthPlusTen); 
     boundNumberProperty.addListener(new ChangeListener<Number>() { 

      @Override 
      public void changed(ObservableValue<? extends Number> observable, 
        Number oldValue, Number newValue) { 
       System.out.println(newValue.toString()); 
      } 

     }); 

    } 

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

} 

更新

任何人都遇到這個問題,可能也想看看托馬斯Mikula的ReactFX,它爲此提供了一個更清潔的解決方法(在使用第三方庫的費用,你需要花一些時間學習)。 Tomas解釋了這個問題,以及ReactFX如何在this blogsubsequent post中解析它。

+5

+1哇! – assylias

+0

非常好!這解決了我的問題。我傾向於信任並依賴於Java中的自動內存/引用管理。顯然太多了:D – underkuerbis

+0

有趣的是,大多數情況下,實際上,在你的示例代碼中,除了簡單類型的測試之外,你真的會使用它來解決問題,問題就會消失。例如,如果您創建一個標籤並將其文本綁定到'IntegerProperty',那麼標籤當然會有效地保留該屬性的引用,所以它不會被垃圾收集。這個問題偶爾會出現在真實場景中,但這種情況非常罕見。 –