Fog Creek Software
Discussion Board




Java listeners...

I'm involved with a few different Java/Swing applications at the moment, and am having some difficulties keeping track of all the listeners involved. Not only is it difficult to debug, but I've found a few significant performance hits that were due to unused listeners.

Is there any easy way of getting a snapshot (at run-time), of all the listeners that are set? As well, any general tools for tracking events, and being able to filter out the applicable ones? (I know there's a huge number of background events going on that don't interest me)

As well, is anyone familiar with a diagramming notation that lets me easily document these control structures?

I'm fairly familiar with Java, but the Swing end of things is a little new to me.

Edward
Friday, August 13, 2004

It never occurred to me to ask, so I don't know off hand.  My guess would be no, there is no way to get a snapshot of all listeners at runtime.

Why do you think "unused listeners" are a performance hit?  What is an "unused listener"?  Is it one that you didn't add to the event generator?  Is it one that is listeneing for events but shouldn't be?

I don't really see where this would be a performance problem.

BTW, when I want to know if a particular listenter is being triggered I just write a block of code (with a flag that can be set when I start the program) that prints a stackTrace when, for example actionPerformed is called.

name withheld out of cowardice
Friday, August 13, 2004

Hmm, bit of a tangent but might be useful:

I had problems with the notify-listeners overhead in some C++ custom objects I had.

I placed the listeners on the collection rather than individual objects within the collection, so that I could coalesce listener notification in sensible ways.  This really helped keep the overhead down.

i like i
Friday, August 13, 2004

Yes, that was poor wording on my part.

Assume my JPanel has a variety of contained widgets and subpanels. I add itemlisteners, changelisteners, documentlisteners, etc to the various contained components, all pointing back to me.

Now in my panel event handlers, I only do something if a certain widget generates a certain event, and ignore the rest. All of these events are still generated, but I'm only really interested in one in particular.

Is there any way of determining at run-time what sort of events are actually being generated? I've come across too many instances where the framework was there for receiving document events, but they weren't actually being used, or only being used very infrequently. Removing the document listeners made quite a bit of difference, performance-wise (I think).

As well, when it comes to refactoring, I've found cases where events were never being generated, but the particular listener interface was still implemented, often because of a change in design (and the developer never removed them). To keep things more simple, I want to remove unused members.

Edward
Friday, August 13, 2004

Edward, any standard profiler ought to be able to capture events when the event object is newed.

Profiling is the way to identify where to put your optimisation effort?

i like i
Friday, August 13, 2004

I have no experience using profilers in Java, but I'm willing to consider it.

Is there a way of setting up a profiler so that I can track exactly;

1. which widgets had which listeners applied at a certain time, and

2. which events were generated by the components contained by a certain panel over a range of time (and be able to filter out non-interesting events) ?

I'm using Eclipse, if that makes any difference.

Edward
Friday, August 13, 2004

You can use Weak Collections for the listener containers. That way if there are no real listener objects anymore (hard references), they would automatically be garbage collected from the collection (which maintains a soft reference).

google for:
java weak listeners

it may give you some pointers.

The Real API
Friday, August 13, 2004

If you create and register a listener you have control over whether you need it or not. You do not have to register a listener just because something supports that type of listner, only if you need to respond to those kinds of events. For example a JFrame generates MouseEvents through it's mouse event listeners but most programs will not need this so they do not register a mouse event listener.

Swing also uses a lot of listeners in the background for its functionality but since you did not create them you can't control them (and shouldn't try). Swing ends up using alot of the listeners that are show in the API that you usually do not use.

So if you are creating event listeners just because, don't create them at all. If you really need the listeners then there is no way to avoid their overhead. Even if you disable the listener temporarily by unregistering it you might still have the memory space taken up until that listener is garbage collected.

You might want to review the Java Tutorial for the Swing API on java.sun.com. They usually provide examples of the most common usage of controls and how to handle their events.

If none of this made sense or didn't help I won't be able to answer better without a more concreate example.

Justin
Friday, August 13, 2004

"So if you are creating event listeners just because, don't create them at all. If you really need the listeners then there is no way to avoid their overhead."

I agree completely. My issue is that when I'm debugging existing code, I really have no convenient way of determining if an event is being monitored at all.

For example, consider abstract class A. A is implemented by B, C, and D. The developer thinks that document events will be monitored, so they add the document listener interface to A. All the text widgets contained in A have A added as a document listener. If B, C, and D do not care about these events, then the widgets still go on merrily firing off events, but nobody is using these events.

Coming into this situation later, it's difficult for me to determine if those events are being used. This is my problem.

Edward
Friday, August 13, 2004

If you only do something if a certain component sends a message than why do you have all the other components send messages that you then ignore?

I also doubt that a few extra messages would result in a significant performance degradation.  There are a lot of things to do to improve a Swing apps apparent performance.  Eliminating a few extra events isn't high on the list, though I suppose there is no reason to send them if you aren't going to respond to them.

name withheld out of cowardice
Friday, August 13, 2004

So you are talking about someone else's code to which you do not have the source?  Are classes B and C your subclasses?  If so you could use them to call removeDocumentListener on the documents in the widgets that keep throwing off these events.

name withheld out of cowardice
Friday, August 13, 2004

"For example, consider abstract class A. A is implemented by B, C, and D. The developer thinks that document events will be monitored, so they add the document listener interface to A. All the text widgets contained in A have A added as a document listener. If B, C, and D do not care about these events, then the widgets still go on merrily firing off events, but nobody is using these events."

This example is still a little vague, how are these text widgets getting registered to A's listener interface? If you are controlling that registration then do not add them. If they have been added not by yourself it would seem that they were added spuriously and that the coder of the base class doesn't know what he's doing. Like I mentioned previously if listeners are registered just for the fun of it without being used then the programmer that did this does not understand them. But if you have access to the source code this is definitely a case where the addXListener(listener) calls should be removed.

Justin
Friday, August 13, 2004

For clarification I'm going to post an example of what would help me understand this problem.

Class A  generates event Foo, so it has methods addFooListener(Foo x)

Class B uses Class A and implements the FooListener interface and then registers itself as a listener for events that an instance of Class A generates

Class C subclasses Class B - since Class B's implementation is based on receiving events from Class A and since that it's already handled in Class B's implementation then this is a valid use of listeners but it's out of your control since you don't want to modify Class B.

Class D is a subclass of Class A, since Class A can have listeners registered on it so can Class D, but events are only sent out if there are registered listeners, otherwise nothing happens. If listeners have been added then they are looped through one at a time and their handleFooEvent messages are called.

Justin
Friday, August 13, 2004

Let's say a certain widget adds class A as a listener. Class A is implemented by B which is implemented by C which is implemented by D which is implemented by E, and so on. Each class may check for a certain event, or just super the event up the chain. Certain instances of Class C will use the event, and opthers will ignore it.

Now say that this widget had 2 or 3 different kinds of listeners, which are added added removed at various times over a certain time.

Now say that you have 20 of these widgets.

How can you possibly determine the effect of removing the addition of a particular listener on a particular widget at a particular time?

I realize that proper documentation would help, but it's not there now. I don't have this problem when starting from scratch; just when looking into existing codebases. When determining the architecture of code at design-time, I can easily see what is calling what, what contains what, etc. With events/listeners, that's just not possible.

Edward
Friday, August 13, 2004

OK that helps, sorry if I'm a bit slow.

Well I have not heard of any tools to make that any easier automagically. The easiest thing I can think of off the top of my head is use Eclipse and right click on the addListener methods of the class an then choose References->Workspace to find all the places that listeners are added and then try to map them out.

If that doesn't help I'm afraid to say you probably going to have to take one class at a time and draw some kind of diagram or chart that maps who uses what and when. There may be tools that can do this for you but I have no knowledge or experience with any. If this is the spagetti code mess it sounds like these kinds of tools may not help that much beacuse the output they would generate would probably be just as hard to understand as the original code or to basic to help in any way.

If you are in a time crunch my condolences, if not just be glad you'll have earned some potential job security.

Justin
Friday, August 13, 2004

Thanks Justin.

I've been doing that sort of thing, but it's a pretty painful process. I was just hoping there was something easier ;-)

It's friday, isn't it.

Edward
Friday, August 13, 2004

Yes but it is also Friday the 13th! =)

Justin
Friday, August 13, 2004

It sounds like a pretty F-cked up design.  You shouldn't, in general find the need to add and remove listeners so frequently and instances that listen should only be listening to events from instances they want to listen to.  It's difficult to tell from here but this shouldn't occur in a good design.  The fact that you have so many levels of inheritance past the basic Swing classes is a bit odd as well.

I find that these messaging chains tend to be pretty short and sweet.  The message generator creates an Event and calls the listener method of between 1 and 5 listening objects.  If an object has this methid called and does nothing before returning it really isn't usually a noticable performance hit.

name withheld out of cowardice
Friday, August 13, 2004

JProbe memory debugger. You can search for, say, all instances of class MyTreeListener. See what holds them. Click and it shows you sourcecode, IIRC.

This is my vague recollection; it really helped me out in quickly tracking down a horrible memory leak due to someone's quick hack in a nonobvious place, where a thread hung around permanently, accumulating references to objects.

Tayssir John Gabbour
Friday, August 13, 2004

*  Recent Topics

*  Fog Creek Home