我经常使用SwingUtilities.invokeLater()
。但是,这样做会使某些情况下的调试变得困难:您无法看到调用SwingUtilities.invokeLater()
的代码的堆栈跟踪,因为该代码已经结束了它的执行。
在调用SwingUtilities.invokeLater()
时,是否有关于如何设置某种上下文(仅用于调试目的)的建议,以便您可以找出导致相关UI事件的原因?
答案 0 :(得分:2)
这里的大多数其他答案都很好,但我想补充一点建议。如果你经常调用SwingUtilities.invokeLater,你可能在某些时候不必要地执行它,特别是如果调用的唯一目的是确保在事件线程上进行Swing更改。请在适当的时候尝试:
if (SwingUtilities.isEventDispatchThread()) {
myRunnable.run();
} else {
SwingUtilities.invokeLater(myRunnable);
}
答案 1 :(得分:2)
您可以尝试覆盖EventQueue
并打印已发布事件的堆栈跟踪。同样在下面的示例中,将为每个发布的事件分配唯一编号。如果从其他invokeLater
调用invokeLater
,则会在日志中打印文本postEvent 9 from 7
// Place this code somewhere in the main class to override queue EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); eventQueue.push(new MyEventQueue());
MyEventQueue类可能如下所示:
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); } }
答案 2 :(得分:1)
覆盖方法,添加日志调用,然后调用真实的... 警告:您必须将所有调用替换为原始方法。
您甚至可以包装runnable并添加上下文编号(例如稍后调用的调用的时间戳)。当runnable启动时,它开始打印上下文编号
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);
}
答案 3 :(得分:1)
我倾向于用更高级的方法替换“标准”swingUtilites#invokeLater方法,也可以嵌入到某些“localUtilities”中,您可以将代码作为参数执行,以源事件或线程执行 - 它的安全副本(我想你有一个源事件,无论它的类型是什么)。
答案 4 :(得分:1)
如果您经常致电invokeLater
,可能需要考虑简化线程。
invokeLater
实际上是使用可变静力学,因此是最纯粹的邪恶。如果您从调用EventQueue.invokeLater
切换到使用invokeLater
和isDispatchThread
的界面,测试及其他内容将变得更加轻松。
遗憾的是,您通常无法替换图书馆使用的invokeLater
和isDispatchThread
。
答案 5 :(得分:1)
您是否将匿名Runnable
传递给invokeLater()
?
如果是,我建议用非匿名类替换它们,这将添加几行代码,但会给你至少一定程度的可追溯性(例如:TableUpdateFromQuery
)。如果您仅从应用程序中的一个位置调用特定类型的更新,则此方法效果最佳。它还引导您走上“后台活动”的道路,可以在UI之外进行测试。