On Fri, 11 Aug 2023 22:03:28 GMT, John Hendrikx <jhendr...@openjdk.org> wrote:
>> Incorporates documentation review comments from #1069. >> >> This PR should be kept minimal so it can be backported to JFX21; it should >> only contain documentation changes. > > John Hendrikx has updated the pull request incrementally with one additional > commit since the last revision: > > Update wording on value subscriber I think that might be better; changing docs on `Observable` and `ObservableValue` is a good idea, but may take some time to get agreement on. I would like to also make clear in such a change when you can expect listener / subscribers to fire, basically documenting the undocumented rules we already have (invalidations fire first then changes; listeners fire in the order they were added, allowing vetoing (which is used in and outside of JavaFX). The general rules would be something like: - Observers on super types fire before observers on sub types (ie. `Observable` before `ObservableValue`) - Observers added on a single type fire in the order they were added (ie. value subscribers, change subscribers and change listeners are not separate lists as they're all offered by `ObservableValue`) I've done an attempt to update the `Observable` class documentation with all recent developments: /** * An {@code Observable} is an entity that wraps content and allows to * observe the content for invalidations. * * <h2>Lazy evaluation and events</h2> * * An implementation of {@code Observable} may support lazy evaluation, * which means that the content is not immediately recomputed after changes, but * lazily the next time it is requested. All bindings and properties in * this library support lazy evaluation. * <p> * Implementations of this class should strive to generate as few events as * possible to avoid wasting too much time in event handlers. Implementations in * this library mark themselves as invalid when the first invalidation event * occurs. They do not generate anymore invalidation events until their value is * recomputed and valid again. * * <h2>Observing an {@code Observable}</h2> * * Observation is possible using listeners and subscribers. These are * interchangeable and have the same semantics: * <li>Observers are notified in the order they were added</li> * <li>When an observer is registered more than once, it will be notified more than once</li> * <li>Observers may be safely registered for different {@code Observable}s</li> * <p> * When observing an {@code Observable}, it will hold a strong reference to the observer which will * prevent it from being garbage collected as long as the {@code Observable} is reachable. * If the lifecycle of the {@code Observable} is longer than a registered observer, care * must be taken to unregister the observer after use to avoid unwanted retention of the * observer, and any other objects it may refer to, in memory (also known as a memory leak). * * <h2>Unregistering observers</h2> * * Unregistering observers when their use ends can be achieved in several ways: * <li>For listeners, call the corresponding {@code removeListener} method, ensuring to pass the exact same instance as was used to register it</li> * <li>For subscribers, call {@link Subscription#unsubscribe()} on each {@link Subscription}, or on a combined subscription</li> * <li>If the {@code Observable} is an {@code ObservableValue}, {@link ObservableValue#when(ObservableValue)} can be used to automatically * decouple the lifecycle of the observer from the original {@code ObservableValue} when a condition (like visibility) holds: * <pre> * {@code * observableValue.when(condition).subscribe(...) * }</pre> * </li> * <li>For listeners, it's possible to use a weak wrapper, like {@link WeakInvalidationListener}, to automatically unregister the listener when it becomes weakly reachable</li> * <p> * Note that the use of weak listener wrappers is no longer recommended when it can be * avoided as it requires intimate knowledge of how weak references work in Java and how * they interact with the garbage collector. The timing of when a weak listener is * unregistered may be very different from the intended or expected timing. It can * depend on many external factors, including the JVM used, its version, its (GC) settings, * but also on the system type and its memory availability. * <li>Garbage collection may be deferred for long periods (or even indefinitely), resulting in weak listeners being removed much later than expected; * until such time, they will keep receiving events, and hold on to any referenced objects</li> * <li>Weak listeners may be cleaned up almost immediately, possibly resulting in a listener being removed if care wasn't taken * to reference it directly</li> * <li>Registering the same or a similar weak listener again may see strange behavior as a previous weak listener may still be present</li> * <p> * The above can lead to hard to reproduce issues that may vary from system to system. * <p> * It is therefore highly recommended to always remove observers which observe an {@code Observable} * that have a longer lifecycle. This can be done either manually (in a clean up or dispose method), * or automatically using a condition with {@code ObservableValue#when}. * * @see javafx.beans.value.ObservableValue * @see javafx.collections.ObservableList * @see javafx.collections.ObservableMap * * * @since JavaFX 2.0 */ ------------- PR Comment: https://git.openjdk.org/jfx/pull/1177#issuecomment-1683728523