I wrote a small runnable JavaFX application with two ways, to listen on size changes of an ObservableList. The first listener (line 52-58) works correct. The second listener (line 60-66) stops working after some events.
You can reproduce this error(?) when you often click the "Add button". The first view clicks, both messages were printed and some clicks later only the first listener further works.
Runnable example:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
final ObservableList<String> list = FXCollections.observableArrayList();
primaryStage.setTitle("Demonstrator");
// Button
Button addButton = new Button();
addButton.setText("Add Element");
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
list.add("TEST");
}
});
// ListView
ListView<String> lv = new ListView<String>();
lv.setItems(list);
// Add elements to root
VBox root = new VBox();
root.getChildren().add(addButton);
root.getChildren().add(lv);
// Show scene
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
// This listener works correct
list.addListener(new ListChangeListener<String>() {
@Override
public void onChanged(Change<? extends String> c) {
System.out.println("#listener1: " + list.size());
}
});
// This listener stops working after 10-30 clicks on the button
Bindings.size(list).addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println("#listener2: " + newValue);
}
});
}
}
I tried it with jdk-8u112-windows-x64 and jdk-8u112-windows-i586
Does anybody have an idea, if there is any mistake in my code, or if it's really a problem with JavaFX?
I got the solution:
The binding was removed from the garbage collector. You have to store the binding as field.
Thanks!
After the line 61 is executed. The instance created in Bindings.size() is not strongly reachable by anything, so it is eligible for garbage collection. It is softly reachable through the listener, but that will not prevent garbage collection.
So eventually it will get garbage collected and stop working.
The solution is: make it strongly reachable, e.g. by storing it in a field in the class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With