On Fri, 11 Aug 2023 22:03:28 GMT, John Hendrikx <[email protected]> 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