Reputation: 189646
I use SwingUtilities.invokeLater()
frequently. Doing so, however, makes it difficult to debug in certain cases: you can't see a stack trace of the code that called SwingUtilities.invokeLater()
, because that code has already ended its execution.
Are there any suggestions for how to set some sort of context (for debugging purposes only) when calling SwingUtilities.invokeLater()
, so that you can figure out what caused the UI event in question?
Upvotes: 5
Views: 1323
Reputation: 26856
Most of the other answers here are good, but I want to add another suggestion. If you are calling SwingUtilities.invokeLater very frequently, you are probably doing it unnecessarily some of the time, especially if the sole purpose of the call is to ensure that Swing changes are made on the event thread. Try this when appropriate:
if (SwingUtilities.isEventDispatchThread()) {
myRunnable.run();
} else {
SwingUtilities.invokeLater(myRunnable);
}
Upvotes: 2
Reputation: 407
You can try to override EventQueue
and print stacktrace for posted events. Also in the example below a unique number would be assigned to each posted event. When invokeLater
would be called from other invokeLater
then the text postEvent 9 from 7
would be printed in the log
// Place this code somewhere in the main class to override queue EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); eventQueue.push(new MyEventQueue());
Where class MyEventQueue might look like this:
import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.event.InvocationEvent; import java.util.WeakHashMap; public class MyEventQueue extends EventQueue { int currentNumber = 0; WeakHashMap<AWTEvent,Integer> eventIdMap = new WeakHashMap<AWTEvent,Integer>(); AWTEvent currentEvent = null; protected void dispatchEvent(AWTEvent event) { if (event instanceof InvocationEvent) { currentEvent = event; } super.dispatchEvent(event); currentEvent = null; } public void postEvent(AWTEvent event) { if (event instanceof InvocationEvent) { currentNumber = currentNumber + 1; eventIdMap.put(event, currentNumber); System.out.println("postEvent " + currentNumber + " " + (currentEvent != null ? "from " + eventIdMap.get(currentEvent) : "") ); for(StackTraceElement element : new RuntimeException().getStackTrace()) { System.out.println("\t" + element); } } super.postEvent(event); } }
Upvotes: 2
Reputation: 147154
If you are calling invokeLater
frequently, you might want to consider simplifying your threading.
invokeLater
is effectively using mutable statics and is therefore purest evil. Testing and more will become easier if you switch from calling EventQueue.invokeLater
to using an interface with invokeLater
and isDispatchThread
.
It is unfortunate that you can't, in general, replace the invokeLater
and isDispatchThread
used by libraries.
Upvotes: 1
Reputation: 2674
Are you passing anonymous Runnable
s to invokeLater()
?
If yes, I'd suggest replacing them with non-anonymous classes, which will add a couple of lines of code, but will give you at least some level of traceability (eg: TableUpdateFromQuery
). This works best if you invoke a particular type of update from only one place in the app. It also leads you down the path of "background activities," which can be tested outside of the UI.
Upvotes: 1
Reputation: 724
Override the method, add a Log call and then call the real one... Caveat : you have to replace all your calls to the original method.
You can even wrap the runnable and add a context number (for example the timestamp of the call to invoke later). When the runnable starts it began to print the context number
public static void myInvokeLater(final Runnable runnable) {
long ts = System.currentTimeMillis();
Log.info("call to invoke later, context :" + ts);
Runnable r = new Runnable() {
public void run() {
Log.info("start runnable of invokeLater with context :" + ts);
runnable.run();
}
};
SwingUtilities.invokeLater(r);
}
Upvotes: 1
Reputation: 22292
I would tend to replace "standard" swingUtilites#invokeLater method by a more advanced one, maybe embedded in some "localUtilities", to which you give both the code to execute with, as an argument, the source event or a thread-safe copy of it (I guess you have a source event, whatever its type is).
Upvotes: 1