Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the listeners in java work?

Tags:

java

javafx

When we add a listener to an Parent object in JavaFx (for example a TextField), what are we really doing under the hood? Are we creating a thread that is observing that particular TextField and when something change, the action by the thread take place?

I get confussed because every single thread program is working in sequence, so how it is possible to watch some variables whenever they change - I assume that something must perform concurrently (?).

like image 312
Michael213 Avatar asked Feb 17 '18 19:02

Michael213


1 Answers

Your assumptions are not correct: there is no threading involved in adding listeners to properties.

JavaFX properties are basically an implementation of the Observer pattern. The implementation used is quite complex, because these properties support "lazy evaluation", meaning that other objects can be notified that the current value is no longer valid, but without recalculating the value unless its requested.

However the basic idea is very simple: the property just keeps a list of listeners and notifies them if the set method is called. The following code is not how StringProperty is implemented in the library, but it will give you an idea what is happening:

public class ExampleStringProperty {

    private final List<ChangeListener<? super String>> changeListeners
        = new ArrayList<>();

    private String value ;

    public String get() {
        return value ;
    }

    public void set(String value) {
        if (! Objects.equals(value, this.value)) {
            String oldValue = this.value ;
            this.value = value ;
            for (ChangeListener<? super String> listener : changeListeners) {
                listener.changed(this, oldValue, value);
            }
        }
    }

    public void addListener(ChangeListener<? super String> listener) {
        changeListeners.add(listener);
    }

    public void removeListener(ChangeListener<? super String> listener) {
        changeListeners.remove(listener);
    }
}

As you can see, no threading is involved: if the property is set, the listeners' changed(...) methods are called on the same thread.

Here's a quick test, using the actual SimpleStringProperty from the library:

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class StringPropertyTest {

    public static void main(String[] args) {
        StringProperty prop = new SimpleStringProperty();
        prop.addListener((obs, oldValue, newValue) -> {
            System.out.printf("Property changed from %s to %s on thread %s%n", 
                    oldValue, newValue, Thread.currentThread());
        });

        System.out.println("Running on thread "+Thread.currentThread());
        System.out.println("Setting property to \"value\"");
        prop.set("value");

        System.out.println("Setting property to \"new value\" on thread "+Thread.currentThread());
        prop.set("new value");
    }
}

which produces the output

Running on thread Thread[main,5,main]
Setting property to "value"
Property changed from null to value on thread Thread[main,5,main]
Setting property to "new value" on thread Thread[main,5,main]
Property changed from value to new value on thread Thread[main,5,main]
like image 172
James_D Avatar answered Oct 03 '22 03:10

James_D