From 852c66497eb39cdbb8e6969bf7b6500d13807548 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sat, 12 Jun 2010 01:15:22 +0000 Subject: [PATCH] Allow adding/removing listeners by weak reference so as not to prevent garbage collection. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6076 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../com/threerings/presents/dobj/DObject.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java index ac05709cd..9c39446d8 100644 --- a/src/java/com/threerings/presents/dobj/DObject.java +++ b/src/java/com/threerings/presents/dobj/DObject.java @@ -21,6 +21,7 @@ package com.threerings.presents.dobj; +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.Arrays; @@ -200,6 +201,31 @@ public class DObject _deathWish = deathWish; } + /** + * Adds a listener using a weak reference that will not prevent the listener from being + * garbage-collected. + */ + public void addWeakListener (ChangeListener listener) + { + if (getWeakListenerIndex(listener) == -1) { + _listeners = ListUtil.add(_listeners, new WeakListenerWrapper(listener)); + } else { + log.warning("Refusing repeat weak listener registration", + "dobj", which(), "list", listener, new Exception()); + } + } + + /** + * Removes a weak event listener. + */ + public void removeWeakListener (ChangeListener listener) + { + int idx = getWeakListenerIndex(listener); + if (idx != -1) { + _listeners[idx] = null; + } + } + /** * Adds an event listener to this object. The listener will be notified when any events are * dispatched on this object that match their particular listener interface. @@ -975,6 +1001,58 @@ public class DObject return null; // key not found. } + /** + * Returns the index of the identified wrapped weak listener, or -1 if not found. + */ + protected int getWeakListenerIndex (ChangeListener listener) + { + if (_listeners == null) { + return -1; + } + for (int ii = 0, ll = _listeners.length; ii < ll; ii++) { + Object olistener = _listeners[ii]; + if (!(olistener instanceof WeakListenerWrapper)) { + continue; + } + if (((WeakListenerWrapper)olistener).ref.get() == listener) { + return ii; + } + } + return -1; + } + + /** + * A listener that wraps a weak reference to another listener. + */ + protected class WeakListenerWrapper + implements EventListener + { + /** The weak reference to our underlying listener. */ + public final WeakReference ref; + + /** + * Creates a new weak listener wrapper. + */ + public WeakListenerWrapper (ChangeListener listener) + { + ref = new WeakReference(listener); + } + + // documentation inherited from interface EventListener + public void eventReceived (DEvent event) + { + ChangeListener listener = ref.get(); + if (listener == null) { + removeListener(this); + } else { + event.notifyListener(listener); + if (listener instanceof EventListener) { + ((EventListener)listener).eventReceived(event); + } + } + } + } + /** Our object id. */ protected int _oid;