package com.jidesoft.swing; import javax.swing.event.ChangeEvent; import java.awt.event.ItemEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.lang.reflect.Method; /** * How to use this: * <code><pre> * KeyboardFocusManager focusManager = * KeyboardFocusManager.getCurrentKeyboardFocusManager(); * <p/> * // instead of registering directly use weak listener * // focusManager.addPropertyChangeListener(focusOwnerListener); * <p/> * focusManager.addPropertyChangeListener( * new WeakPropertyChangeListener(focusOwnerListener, focusManager)); * </pre></code> * <p/> * How does this work: * <p/> * Instead of registering propertyChangeListener directly to keyboardFocusManager, we wrap it inside * WeakPropertyChangeListener and register this weak listener to keyboardFocusManager. This weak listener acts a * delegate. It receives the propertyChangeEvents from keyboardFocusManager and delegates it the wrapped listener. * <p/> * The interesting part of this weak listener, it hold a weakReference to the original propertyChangeListener. so this * delegate is eligible for garbage collection which it is no longer reachable via references. When it gets garbage * collection, the weakReference will be pointing to null. On next propertyChangeEvent notification from * keyboardFocusManager, it find that the weakReference is pointing to null, and unregisters itself from * keyboardFocusManager. Thus the weak listener will also become eligible for garbage collection in next gc cycle. * <p/> * This concept is not something new. If you have a habit of looking into swing sources, you will find that * AbstractButton actually adds a weak listener to its action. The weak listener class used for this is : * javax.swing.AbstractActionPropertyChangeListener; This class is package-private, so you don't find it in javadoc. * <p/> * The full-fledged, generic implementation of weak listeners is available in Netbeans OpenAPI: WeakListeners.java . It * is worth to have a look at it. * * @author Santhosh Kumar T - santhosh@in.fiorano.com */ public class WeakPropertyChangeListener implements PropertyChangeListener { private WeakReference<PropertyChangeListener> _listenerRef; private Object _src; public WeakPropertyChangeListener(PropertyChangeListener listener, Object src) { _listenerRef = new WeakReference(listener); _src = src; } public void propertyChange(PropertyChangeEvent evt) { PropertyChangeListener listener = _listenerRef.get(); if (listener == null) { removeListener(); } else listener.propertyChange(evt); } public void itemStateChanged(ItemEvent e) { } public void stateChanged(ChangeEvent e) { } private void removeListener() { try { Method method = _src.getClass().getMethod("removePropertyChangeListener" , new Class[]{PropertyChangeListener.class}); method.invoke(_src, new Object[]{this}); } catch (Exception e) { e.printStackTrace(); } } }