jeudi 27 juin 2013

FXBinding, the binding you need

JavaFX 2 brings the Properties and Bindings concepts. If you don't know what I am talking about, I suggest you to have a look here : binding

I have an List ObservableList<XYChart.Data<Number, Number>>. I want to compute the average value of XValueProprerty for all Data contained into the list :

Without FXBinding :

See full code here

As you can see, it doesn't work :/

The binding is invalid only when the list changes, so when the XValue of a Data changes, nothing append.

I have to register every XValueProperty() into the bind() method :

See full code here

Now it works for all Data that was into the list at the beginning, but not for all added (or removed) Data after the init of the Binding

Let's make it work :

See full code here

While the complexity of your model is growing, you will have to register many listeners and the code is going to be less readable, less maintainable and less bug proof.

With FXBinding

Now let's replace our DoubleBinding by a magical FXDoubleBinding, it's 4 time step :

  • Replace new DoubleBinding() by new FXDoubleBinding()
  • Change the method name from computeValue() to compute()
  • Remove {bind(...)} and replace it by the configure() method
  • In the configure() method call addObservable() instead of bind()
See full code here

Every time the binding is becoming invalid, we will reconfigure it, so it's always a cool binding.

We will never have to add a listener even in a very complex model

An other example :

See full code here

Get FXBinding here

jeudi 20 juin 2013

ListProperty vs ObjectProperty

In the world of JavaFX, when you need to use an ObservableList with the Property pattern, you write the following :


To be notified when the list content is modified, you can register a ListChangeListener on the ObservableList referenced by the ObjectProperty using the getter.
You can also register a ChangeListener on the ObjectProperty to be notified when the instance of ObservableList referenced by the ObjectProperty is modified.

You will end up with something like that :

  • If you add an element or more, your ListChangeListener will be notified.
  • If you change your ObservableList instance, your ChangeListener will be called.
But if the ObservableList instance referenced by the ObjectProperty has changed, and you try to add some elements to the new list instance, you won't be notified. This is because your ListChangeListener  is still registered on the previous ObservableList instance. So in your ChangeListener you have to unregister your ListChangeListener from the old ObservableList instance and register it to the new one. It's a little bit boring to do each time...

A major issue we discovered, is that if you replace an empty ObservableList by an other empty ObservableList, the ChangeListener is not notified, as we can see on this unit test, so that you can't correctly re-register the ListChangeListener on the new instance:

Why ? cause the equals method implementation return true between the two ObservableList.

So as you see... using an ObservableList with the Property pattern, is not really cool.

This is a problem, isn't it ??

Oh Legolas wants to help us. So listen what he says:

Replace our ObjectProperty<ObservableList<T> by a ListProperty<T>. ListProperty implements both Property<ObservableList> and ObservableList and makes the whole wrapping really transparent for the developer, taking care of the previous ListChangeListener manipulation automatically !
With that, if you want to be notified when the content of the List is modified, you just need to register the ListChangeListener once.

Like that :

When you do this, adding an element will notify the listener, and changing the ObservableList instance will call the listener to. And if you add an element after changing the list instance, no problem! the listener will also be notified of the change in the new list instance. No need to register a new Listener on the new List, the ListProperty manages it for you !

This unit test show us the ListChangeListener is called 5 times, once on each change.

Now you are ready to replace your ObjectProperty<ObservableList> by ListProperty ! Have fun