Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8194173

AnimationTimer can call handle() more than 60 times a second when window is resized

XMLWordPrintable

    • generic
    • generic

      FULL PRODUCT VERSION :
      java 9.0.1
      Java(TM) SE Runtime Environment (build 9.0.1+11)
      Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      macOS 10.13.2

      Also tested and reproduced on windows

      A DESCRIPTION OF THE PROBLEM :
      Run the attached code.

      The ball will appear to bounce smoothly.

      Begin resizing the window and you'll notice the ball begins to move faster and the console reports a FPS greater than 60.

      In many online discussions, it has been stated that the AnimatiomTimer class will only call handle() at most 60 times per second but that is not true.

      In https://docs.oracle.com/javafx/2/architecture/jfxpub-architecture.htm too it says that the pulses are throttled at 60 times per second.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The description is pretty clear.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The number of times handle() is called per second to cap at 60.
      ACTUAL -
      The number of times handle() is called per second is not capped at 60.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package sample;

      import javafx.animation.AnimationTimer;
      import javafx.application.Application;
      import javafx.scene.Group;
      import javafx.scene.Scene;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Circle;
      import javafx.stage.Stage;

      import java.util.concurrent.TimeUnit;

      public class Main extends Application {

          final int WIDTH = 600;
          final int HEIGHT = 400;

          double ballRadius = 40;
          double ballX = 100;
          double ballY = 200;
          double xSpeed = 4;

          long framesInSecond = 0;
          long nextSecond = 0;
          final long SECOND = TimeUnit.SECONDS.toNanos(1);

          @Override
          public void start(Stage stage) throws Exception {
      // Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
      // primaryStage.setTitle("Hello World");
      // primaryStage.setScene(new Scene(root, 300, 275));
      // primaryStage.show();


              stage.setTitle("Basic JavaFX demo");

              Group root = new Group();
              Scene scene = new Scene(root, WIDTH, HEIGHT);

              Circle circle = new Circle();
              circle.setCenterX(ballX);
              circle.setCenterY(ballY);
              circle.setRadius(ballRadius);
              circle.setFill(Color.BLUE);
              root.getChildren().add(circle);

              stage.setScene(scene);
              stage.show();

      // final KeyFrame frame = new KeyFrame(Duration.millis(1000/60), new EventHandler<ActionEvent>() {
      // public void handle(javafx.event.ActionEvent e) {
      // // UPDATE
      // ballX += xSpeed;
      //
      // if (ballX + ballRadius >= scene.getWidth()) {
      // ballX = scene.getWidth() - ballRadius;
      // xSpeed *= -1;
      // } else if (ballX - ballRadius < 0) {
      // ballX = 0 + ballRadius;
      // xSpeed *= -1;
      // }
      //
      // // RENDER
      // circle.setCenterX(ballX);
      // }
      // });
      //
      // Timeline timeline = new Timeline();
      // timeline.setCycleCount(Animation.INDEFINITE);
      // timeline.getKeyFrames().addAll(frame);
      // timeline.play();

              AnimationTimer animator = new AnimationTimer() {
                  @Override
                  public void handle(long nanos) {
                      framesInSecond++;
                      if (nanos >= nextSecond) {
                          nextSecond = nanos + SECOND;
                          System.out.println(framesInSecond);
                          framesInSecond = 0;
                      }
                      ballX += xSpeed;

                      if (ballX + ballRadius >= scene.getWidth()) {
                          ballX = scene.getWidth() - ballRadius;
                          xSpeed *= -1;
                      } else if (ballX - ballRadius < 0) {
                          ballX = 0 + ballRadius;
                          xSpeed *= -1;
                      }

                      circle.setCenterX(ballX);
                  }
              };

              animator.start();
          }


          public static void main(String[] args) {
              launch(args);
          }
      }
      ---------- END SOURCE ----------

            kcr Kevin Rushforth
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: