Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Sunday, August 16, 2015

Focus Listener on JavaFX Text Fields that Avoids Memory Leaks

This is a code snippet showing how to add a focus out listener to your JavaFX TextFields.  This example presents a pair of PasswordFields that need to call methods when they lose focus in order to complete a form.  The documentation warns about a memory leak involved with this type of snippet and this MUST be taken seriously, although you may not notice a problem.

This form requires a pair of passwords to be entered.  Each password is linked to a confirmation.  When the confirmation is committed (the return key), I have methods "verifyStorepass" and "verifyKeypass" that are called.  This is set up in SceneBuilder.

However, verifyStorepass and verifyKeypass need to be called in cases where the user navigates out of the controls.  Users are conditioned to tab around a form and may also use a mouse or touch to fill out a form.  So, the users may not get the SceneBuilder-set onAction to fire.

I use an InvalidationListener to trigger the focusing behavior.  I'm using this rather than a ChangeListener since I don't need to know the value of the TextField.  I'm only concerned with the event, noting that the user interacted with the form.  See this post on some observations involving InvalidationListener and ChangeListener.

PasswordFields with Confirmations
The Javadoc warns against a memory leak when using the addListener() method on the PasswordField.  You have two options to fend this off: save the listener object and remove it in a finalize() overridden method or use a WeakInvalidationListener.  I prefer the WeakInvalidationListener because it doesn't require the extra follow up code.

InvalidationListener pfConfStorepassListener = (evt) -> {
 if( !pfConfStorepass.isFocused() ) {
  verifyStorepass();
 };
};
   
pfConfStorepass.focusedProperty().addListener(
 new WeakInvalidationListener(pfConfStorepassListener)
);

The InvalidationListener checks the focused property of the PasswordField.  I only want the verify call to be made on the focus out even (focused=false).  The listener is saved as an object and wrapped-up en route to being added to the focusedProperty.

The problem with a memory leak is that it can be extremely difficult to troubleshoot and can show up in the worst time.  That is, you may find it much later than it was introduced and waste a lot of time looking at recent changes that are distractions.  The only way to fend off memory leaks reliably is through coding standards, using weak references wherever possible to help the garbage collector untangle bidirectional relationships.

No comments:

Post a Comment