Wednesday 12 September 2012

JavaFX Help: Too much animation at the same time!

I am currently working on building a Java memory model teaching tool in JavaFX, the project is available on GitHub. Whilst building the user interface I ran into a performance issue, which is easily worked around using JavaFX. This post gives the detail to the problem and how to easily resolve it.

In the memory model we have several memory sections made of memory blocks. In our application we represent each memory block with a StackPane. This has a Rectangle object at the bottom and a Text object on top of this to represent the current generation that block is in.

A block has three states it can be in:
  • Free - nothing has been allocated here yet.
  • Alive - the block holds some active memory.
  • Dead - the memory in the block has now died and is awaiting garbage collection.

We have potentially several threads that are running against the model allocating and killing memory. The challenge is animating each of the state transitions on the UI. A picture shows the animation in action:


The code segment that we used for the transition is as follows (there might be a better way to do this):

     FadeTransition fadeOldBlockOut = new FadeTransition(Duration.millis(10), view);  
     fadeOldBlockOut.setFromValue(1.0);  
     fadeOldBlockOut.setToValue(0.0);  
     fadeOldBlockOut.setCycleCount(1);  
     fadeOldBlockOut.setAutoReverse(false);  
     fadeOldBlockOut.play();
  
     FadeTransition fadeNewBlockIn = new FadeTransition(Duration.millis(1500), view);  
     fadeNewBlockIn.setFromValue(0.0);  
     fadeNewBlockIn.setToValue(1.0);  
     fadeNewBlockIn.setCycleCount(1);  
     fadeNewBlockIn.setAutoReverse(false);  
     fadeNewBlockIn.setDelay(Duration.millis(1));  
     fadeNewBlockIn.play();   

This code was added to the view object. However, once you get multiple of these firing the application will quickly start to hurt itself to keep up with the transitions required. Having read Java FX Pro 2 I quickly realised that I had taken the wrong approach. Large amounts of updating graphics, especially timeline style animation, does not belong on the main application thread. Thankfully JavaFX has an easy paradigm to resolve the issue.

I created an Object that implements Runnable, which would take the memory block I want to animate in the constructor and perform the logic above:

 class CustomMemoryBlockViewTransition implements Runnable {  
   private final MemoryBlockView view;  
   public CustomMemoryBlockViewTransition(MemoryBlockView view_) {  
     view = view_;  
   }  
   @Override  
   public void run() {  
     //...  
   }  
 }  

Once you have your Runnable defined (you can also do this as an anonymous inner class) you can simply call the Platform to run the animation at a later point. The Platform keeps a queue of activities submitted and will execute these in order.

 Platform.runLater(new CustomMemoryBlockViewTransition(this));  


No comments:

Post a Comment