Reputation: 1439
I'm using JavaFx that comes with JDK 8.0, on a MacBook Pro with 2,4 GHz Intel Core 2 Duo processor and 4GB of RAM.
I have a strange behavior, using the following class:
import com.sun.javafx.perf.PerformanceTracker;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
private static PerformanceTracker tracker;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene= new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
Label label1 = new Label();
Label label2 = new Label();
((Pane)root).getChildren().addAll(label1, label2);
scene.setOnKeyPressed((e)->{
label2.setText(label1.getText());
});
tracker = PerformanceTracker.getSceneTracker(scene);
AnimationTimer frameRateMeter = new AnimationTimer() {
@Override
public void handle(long now) {
label1.setText(String.format("Current frame rate: %.3f fps", getFPS()));
}
};
//frameRateMeter.start();
}
private float getFPS () {
float fps = tracker.getAverageFPS();
tracker.resetAverageFPS();
return fps;
}
}
This code when executed uses CPU between a percentage of 0.2% to max 10%. If I remove the comment from :
frameRateMeter.start();
I get that the same code uses CPU from 20% to 40%.
This is just an example but, the application I wrote, commenting out the line above, runs using around 40% of CPU and removing the comment runs near 100% of CPU.
Is that normal? I notice that also adding any time of Timeline (also very simple one) that execute continuously, produces a ridiculous use of CPU.
Is really so expensive to use animation in JavaFX or there is something I have missed?
Any help would be really appreciate.
Upvotes: 3
Views: 1601
Reputation: 7255
Here is an easy way to count FPS[frames per second] from AnimationTimer
without using any other class:
/**
* AnimationTimer .
*
* @author GOXR3PLUS
*/
public class PaintService extends AnimationTimer {
/** The next second. */
long nextSecond = 0L;
/** The Constant ONE_SECOND_NANOS. */
private static final long ONE_SECOND_NANOS = 1_000_000_000L;
/**
* When this property is <b>true</b> the AnimationTimer is running
*/
private volatile SimpleBooleanProperty running = new SimpleBooleanProperty(false);
@Override
public void start() {
nextSecond = 0L;
super.start();
running.set(true);
}
@Override
public void stop() {
super.stop();
running.set(false);
}
/**
* @return True if AnimationTimer is running
*/
public boolean isRunning() {
return running.get();
}
/**
* @return Running Property
*/
public SimpleBooleanProperty runningProperty() {
return running;
}
@Override
public void handle(long nanos) {
// -- Show FPS if necessary.
if (true) { //originally i had a variable (showFPS) here
framesPerSecond++;
// Check for 1 second passed
if (nanos >= nextSecond) {
fps = framesPerSecond;
framesPerSecond = 0;
nextSecond = nanos + ONE_SECOND_NANOS;
}
label.setText("FPS: " + fps);
}
}
}
Upvotes: 1
Reputation: 9981
I think you are updating FPS value in Label very frequently:
The class AnimationTimer allows to create a timer, that is called in each frame while it is active.
When you update text in the label1
the JavaFX draw new frames again and again. You can easy check this: write FPS to STDOUT instead of label1
:
...
System.out.println(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
// label1.setText(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
...
In this case you should see less FPS rate.
So, try to update FPS value every one or half second use any Java/JavaFX timer i.e.:
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), event -> {
label1.setText(String.format("Current frame rate: %.3f fps", tracker.getAverageFPS()));
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
Average CPU value is about 1.8-2% on my macOS.
Upvotes: 2