Feedback requested for infrastructure for properties that wish to delay registering listeners

John Hendrikx john.hendrikx at gmail.com
Sun Feb 5 09:45:59 UTC 2023


Any comments on this?

I think having API to make it easier for both JavaFX and users to create 
listeners that can delay registration to their own dependencies. This 
would be an alternative to using weak listeners for these cases.

--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