HEADS-UP: Threading restriction for Animation play, pause, stop now enforced

Jurgen Doll javafx at ivoryemr.co.za
Tue Jan 23 11:02:19 UTC 2024


Hi Michael

> starting an animation on a background thread would only be safe if the
> object graph affected by the animation is not accessed on the
> background thread after calling the play() method. Any access may
> potentially corrupt internal state.

Agreed. Actually we should drive this further and say that "No changes  
should be made to properties that are being 'animated' while animation is  
in progress regardless of whether you're on the FX thread or not, or if  
the object is in the scene graph or not".

         updater.play();
         memoryLabel.setStyle( "-fx-text-fill: green" );  // This is OK
         memoryLabel.setText( "This is NOT okay" );  // This is NOT, move  
to before play

Interesting API idea, however I don't think it's really needed for  
sensible developers.

Regards
Jurgen


On Mon, 22 Jan 2024 22:53:48 +0200, Michael Strauß  
<michaelstrau2 at gmail.com> wrote:

> Hi Jurgen,
>
> starting an animation on a background thread would only be safe if the
> object graph affected by the animation is not accessed on the
> background thread after calling the play() method. Any access may
> potentially corrupt internal state.
>
> From what I can see in your example, you're not doing anything with
> TestView after starting the animation, so you should be good here.
>
> From an API perspective, I wonder if that makes it too easy to
> introduce subtle bugs into an application. As a general principle, I
> think an API should make it easy to do the right thing, and hard to do
> the wrong thing. Allowing potentially unsafe method calls without some
> explicit procedure (like wrapping the call in Platform.runLater) might
> not be a good idea.
>
> Maybe we should provide an API that allows developers to safely modify
> an object graph on a background thread and call Platform.runLater
> without worrying about concurrent modifications.
>
> Something like this:
>
> try (var scope = Platform.deferredScope()) {
>     var updater = new Timeline(
>        new KeyFrame(Duration.seconds(2.5), event ->
>        {
>           int maxMemory = ....;
>           int usedMemory = ....;
>           memoryLabel.setText(usedMemory + " MB / "+ maxMemory +" MB");
>        })
>     );
>
>     // This call will only be dispatched after the deferred scope is  
> closed:
>     scope.runLater(updater::play);
>
>     // Still safe to call in the deferred scope, wouldn't be safe if
>     // Platform.runLater had been called before:
>     memoryLabel.setText("N/A");
> }


More information about the openjfx-dev mailing list