Search code examples
javafxpropertieslistener

JavaFX property remove listener not working


I try to add, remove and add again a listener to a JavaFX BooleanProperty but it is not working.

Here is my code

public class PropListenerTest {

    BooleanProperty test = new SimpleBooleanProperty(false);

    public PropListenerTest() {
        System.out.println("\nTest 1\tadd the listener"); //NON-NLS
        test.addListener(this::onChangeTest);
        test.set(true);
        test.set(false);

        System.out.println("\nTest 2\tremove the listener, but not possible! Why?"); //NON-NLS
        test.removeListener(this::onChangeTest);
        test.set(true);
        test.set(false);

        System.out.println("\nTest 3\tAdd the listener again, but now i have two listener but I want only one!"); //NON-NLS
        test.addListener(this::onChangeTest);
        test.set(true);
        test.set(false);
    }

    private void onChangeTest(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
        System.out.println("observable = [" + observable + "], oldValue = [" + oldValue + "], newValue = [" + newValue + "]"); //NON-NLS
    }

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

The result is the following

Test 1  add the listener
observable = [BooleanProperty [value: true]], oldValue = [false], newValue = [true]
observable = [BooleanProperty [value: false]], oldValue = [true], newValue = [false]

Test 2  remove the listener, but not possible! Why?
observable = [BooleanProperty [value: true]], oldValue = [false], newValue = [true]
observable = [BooleanProperty [value: false]], oldValue = [true], newValue = [false]

Test 3  Add the listener again, but now i have two listener but want only one
observable = [BooleanProperty [value: true]], oldValue = [false], newValue = [true]
observable = [BooleanProperty [value: true]], oldValue = [false], newValue = [true]
observable = [BooleanProperty [value: false]], oldValue = [true], newValue = [false]
observable = [BooleanProperty [value: false]], oldValue = [true], newValue = [false]

I think in Test 2 there should be no result and in Test 3 it should display the same result as in Test 1. I don't know what I am doing wrong. Can someone help me?

Thanks


Solution

  • The method reference will act as though it creates a distinct object each time.

    Imagine doing

    ChangeListener<Boolean> changeListener1 = new ChangeListener() {
        @Override
        public void changed(Observable<? extends Boolean> obs, Boolean oldValue, Boolean newValue) { }
    };
    
    ChangeListener<Boolean> changeListener2 = new ChangeListener() {
        @Override
        public void changed(Observable<? extends Boolean> obs, Boolean oldValue, Boolean newValue) { }
    };
    

    then changeListener1 == changeListener2 and changeListener1.equals(changeListener2) would be false.

    Similarly,

    ChangeListener<Boolean> changeListener1 = this::onChangeTest ;
    ChangeListener<Boolean> changeListener2 = this::onChangeTest ;
    

    would also result in changeListener1 == changeListener2 being false.

    If you do

    ChangeListener<Boolean> changeListener = this::onChangeTest ;
    
    System.out.println("\nTest 1\tadd the listener"); //NON-NLS
    test.addListener(changeListener);
    test.set(true);
    test.set(false);
    
    System.out.println("\nTest 2\tremove the listener, but not possible! Why?"); //NON-NLS
    test.removeListener(changeListener);
    test.set(true);
    test.set(false);
    
    System.out.println("\nTest 3\tAdd the listener again, but now i have two listener but I want only one!"); //NON-NLS
    test.addListener(changeListener);
    test.set(true);
    test.set(false);
    

    it will behave as you expect.