LiveList is called twice when updating

151 views Asked by At

I'm using LiveList to bind the children of a group to a list containing the data of the children. here is an example:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        ObservableList<Integer> intList = FXCollections.observableArrayList();
        LiveList<Circle> circleList = LiveList.map(intList, i -> {
            System.out.println("in");
            return new Circle(i);
        });

        Group group = new Group();
        Bindings.bindContent(group.getChildren(), circleList);

        intList.add(2);
        intList.clear();
    }

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

My problem is that for each change in intList the bound list is updated twice and which creates more objects than needed. Running the code gives:

in
in
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Children: duplicate children added: parent = Group@68887c42
    at javafx.scene.Parent$2.onProposedChange(Parent.java:454)
    at com.sun.javafx.collections.VetoableListDecorator$VetoableSubListDecorator.clear(VetoableListDecorator.java:529)
    at com.sun.javafx.binding.ContentBinding$ListContentBinding.onChanged(ContentBinding.java:114)
    at org.reactfx.collection.ChangeListenerWrapper.onChange(LiveList.java:439)
    at org.reactfx.collection.ChangeListenerWrapper.onChange(LiveList.java:417)
    at org.reactfx.util.ListNotifications.lambda$takeHead$0(NotificationAccumulator.java:317)
    at org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:68)
    at org.reactfx.ObservableBase.notifyObservers(ObservableBase.java:57)
    at org.reactfx.collection.MappedList.sourceChanged(MappedList.java:41)
    at org.reactfx.collection.LiveList.lambda$observeQuasiChanges$7(LiveList.java:256)
    at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
    at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
    at test1.Main.start(Main.java:27)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:748)

I want that for each element in intList there will be a Circle in the group's children. Why does this happen and how can I make it work properly?

1

There are 1 answers

7
Itai On

The exception description is a red herring - the message "duplicate children added" is given whenever at the end of the change the number of children doesn't match what the change predicted it to be.
In your case, what actually happens is that the circle is not removed, so the Group ends up with a single child, yet clear predicted it should have ended with 0.

The reason why the circle is not removed is that it is not the same circle - your mapper creates a new Circle object whenever it is asked to perform the mapping, and so you get 1 circle when adding it, and a completely different one when clearing the list - this new Circle cannot be removed from the children of the group, and so it remains with 1 child even after the call to clear, triggering the exception.

To solve this you would have to make sure you return the same target-object for the same source-object - this may not be possible if your list of integers may contain duplicates.