* Try to always use a weak listener, even though it's extra typing. The classes of bugs you are exposed to with strong listeners are mostly running out of memory, taxing the garbage collector, and killing performance as you take memory off the heap -- they creep up and are hard to detect. The classes of bugs with weak listeners are functionally worse -- but easy to detect -- stuff just doesn't work because the listeners got GCed (they are a little less performant too, due to tracking their weak-ness).
* When writing weak listeners: Make sure that objects you are listening on will not get prematurely garbage collected and are attached to something -- either the class, or some static Singleton.
* Make sure the object will get garbage collected eventually and write a comment about it.
* Assume that all weak listeners and objects will never get GC'd and will keep listening forever -- code for this. In other words, explicitly remove listeners when it is IMPERATIVE that you do not receive any more messages, do not rely on setting a parent to null to break the cycle.
* You DO NOT have to remove weak listeners if it doesn't matter if they continue to receive events until they GC -- e.g. a mouse move handler -- once you've removed the object from the display list, it doesn't matter that this handler MIGHT run. If you code your handlers to guard against runtime errors, then you never have to remove weak listeners. And if the listeners are still receiving after a long while... then you have a memory leak and the object you are listening on is not getting GC'd (see this post).
* If you are going to skip removing a listener, DOCUMENT IT at the line where you add the listener. If you won't document it, then don't do it.
* This is tricky stuff, so treat listeners with respect like you would NEW and DELETE in C++. Work them out in your head -- document the hell out of them. They are expensive and cause almost all memory and (many) performance leaks.