Feedback requested for infrastructure for properties that wish to delay registering listeners
John Hendrikx
john.hendrikx at gmail.com
Tue Feb 7 14:43:08 UTC 2023
I've made a draft PR which shows the changes I'm proposing below.
For those interested, it can be found here:
https://github.com/openjdk/jfx/pull/1023
--John
On 19/01/2023 16:49, John Hendrikx wrote:
> Hi list,
>
> I've been looking into what it would take to make the design of
> properties which only register listeners when needed easier to
> implement with JavaFX, both for JavaFX itself as well as for the
> user. This is the result of my investigation into ListProperty (and
> other collection properties) and how hard it would be to change their
> semantics to only register listeners when they're absolutely required
> for the correct functioning of the class.
>
> Currently, JavaFX doesn't offer the tools one would need to register
> listeners in a just-in-time fashion. This is because there is no
> notification mechanism available in its observable values when they
> become observed or unobserved. The closest thing there currently
> exists is what ObjectBinding and LazyObjectBinding offer:
>
> From ObjectBinding:
>
> /**
> * Checks if the binding has at least one listener registered on
> it. This
> * is useful for subclasses which want to conserve resources when
> not observed.
> *
> * @return {@code true} if this binding currently has one or more
> * listeners registered on it, otherwise {@code false}
> * @since 19
> */
> protected final boolean isObserved() {
> return helper != null;
> }
>
> From LazyObjectBinding:
>
> /**
> * Called after a listener was added to start observing inputs if
> they're not observed already.
> */
> private void updateSubscriptionAfterAdd() { ... }
>
> /**
> * Called after a listener was removed to stop observing inputs if
> this was the last listener
> * observing this binding.
> */
> private void updateSubscriptionAfterRemove() { ... }
>
> I'm proposing to extend the JavaFX with new methods that can be used
> to stay informed about the observable's current observed status. These
> methods will facilitate implementations of properties that wish to
> delay registering listeners until they are themselves observed. This
> can save memory, save unnecessary notifications via events and reduces
> the need for weak listener constructs.
>
> The proposal does not require any new fields, and would default to
> reporting observable values as being observed. Most JavaFX observable
> values should be retrofitted to support this functionality -- the ones
> relying on a form of ExpressionHelper will only require minimal
> changes with minimal impact.
>
> The methods that I would like to see added are the following:
>
> In ObservableValue:
>
> /**
> * Checks if this ObservableValue is currently observed. If
> unknown or unsupported,
> * {@code true} is returned.
> *
> * @return {@code true} if this ObservableValue currently has one
> or more
> * listeners registered on it, otherwise {@code false}
> */
> default boolean isObserved() { return true; }
>
> The above method is useful for debugging, but its primary use is for
> complex properties which observed status is determined by not only its
> direct listeners but also any child properties it may offer.
> ListProperty is such an example, which offers child properties size
> and empty. Its observed status would be determined like this:
>
> helper != null || (size0 != null && size0.isObserved()) ||
> (empty0 != null && empty0.isObserved())
>
> Further, we need two protected callback methods. These should be
> added in all Binding and Property Base classes (basically all classes
> that implement addListener/removeListener methods). These are called
> when the observed status of the property changes:
>
> /**
> * Called when this property transitions from unobserved to observed.
> */
> protected void observed() {}
>
> /**
> * Called when this property transitions from observed to unobserved.
> */
> protected void unobserved() {}
>
> These methods are implemented by child properties in order to inform
> the parent that their observed status has changed, which may require
> the parent property to change its status as well.
>
> When implemented, LazyObjectBinding can be simplified as some or all
> of its functionality will be part of ObjectBinding (LazyObjectBinding
> is not a public class at the moment). The isObserved method in
> ObjectBinding would go from protected to public (it's already final).
>
> Implementation for classes that rely on a form of ExpressionHelper is
> simple; they can check if the helper is null or not (for isObserved)
> and check if the nullity changed during addListener/removeListener
> calls to make their call to "observed" or "unobserved". No additional
> fields are required.
>
> I've added a proof of concept here
> (https://github.com/openjdk/jfx/pull/1004) where `ListPropertyBase`
> was altered to use these new methods to delay its listener
> registration and to remove its listener when no longer observed. This
> PoC includes the tests written by Florian Kirmaier which fail on the
> current ListProperty implementation (but pass with this version).
>
> --John
>
More information about the openjfx-dev
mailing list