我SwingUtilities.invokeLater()
经常使用。但是,这样做会使在某些情况下难以调试:您看不到调用 的代码的堆栈跟踪SwingUtilities.invokeLater()
,因为该代码已经结束了其执行。
是否有关于在调用时如何设置某种上下文(仅用于调试目的)的建议SwingUtilities.invokeLater()
,以便您找出导致相关 UI 事件的原因?
我SwingUtilities.invokeLater()
经常使用。但是,这样做会使在某些情况下难以调试:您看不到调用 的代码的堆栈跟踪SwingUtilities.invokeLater()
,因为该代码已经结束了其执行。
是否有关于在调用时如何设置某种上下文(仅用于调试目的)的建议SwingUtilities.invokeLater()
,以便您找出导致相关 UI 事件的原因?
您可以尝试覆盖EventQueue
并打印已发布事件的堆栈跟踪。同样在下面的示例中,将为每个发布的事件分配一个唯一编号。什么时候invokeLater
从其他地方调用invokeLater
然后文本postEvent 9 from 7
将打印在日志中
// 将此代码放在主类中的某个位置以覆盖队列 EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); eventQueue.push(new MyEventQueue());
MyEventQueue 类可能如下所示:
导入 java.awt.AWTEvent; 导入 java.awt.EventQueue; 导入 java.awt.event.InvocationEvent; 导入 java.util.WeakHashMap; 公共类 MyEventQueue 扩展 EventQueue { int currentNumber = 0; WeakHashMap<AWTEvent,Integer> eventIdMap = new WeakHashMap<AWTEvent,Integer>(); AWTEvent currentEvent = null; 受保护的无效调度事件(AWTEvent事件){ 如果(事件实例InvocationEvent){ 当前事件 = 事件; } super.dispatchEvent(事件); 当前事件 = 空; } 公共无效postEvent(AWTEvent事件){ 如果(事件实例InvocationEvent){ 当前编号 = 当前编号 + 1; eventIdMap.put(event, currentNumber); System.out.println("postEvent " + currentNumber + " " + (currentEvent != null ? "来自 " + eventIdMap.get(currentEvent) : "") ); for(StackTraceElement 元素:新 RuntimeException().getStackTrace()) { System.out.println("\t" + 元素); } } super.postEvent(事件); } }
这里的大多数其他答案都很好,但我想添加另一个建议。如果您非常频繁地调用 SwingUtilities.invokeLater,那么您可能在某些时候这样做是不必要的,特别是如果调用的唯一目的是确保在事件线程上进行 Swing 更改。在适当的时候试试这个:
if (SwingUtilities.isEventDispatchThread()) {
myRunnable.run();
} else {
SwingUtilities.invokeLater(myRunnable);
}
覆盖该方法,添加一个 Log 调用,然后调用真正的方法......警告:您必须将所有调用替换为原始方法。
您甚至可以包装可运行文件并添加上下文编号(例如稍后调用的调用的时间戳)。当 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);
}
我倾向于用更高级的方法替换“标准”swingUtilites#invokeLater 方法,可能嵌入在一些“localUtilities”中,您可以将要执行的代码作为参数提供给源事件或线程安全副本其中(我猜你有一个源事件,无论它的类型是什么)。
您是否将匿名Runnable
s 传递给invokeLater()
?
如果是,我建议将它们替换为非匿名类,这将添加几行代码,但至少会给您一定程度的可追溯性(例如:)TableUpdateFromQuery
。如果您仅从应用程序中的一个位置调用特定类型的更新,则此方法效果最佳。它还引导您走上“后台活动”的道路,可以在 UI 之外进行测试。
如果您invokeLater
经常调用,您可能需要考虑简化线程。
invokeLater
有效地使用了可变静态,因此是最纯粹的邪恶。如果您从调用切换EventQueue.invokeLater
到使用带有invokeLater
和的接口,测试和更多操作将变得更加容易isDispatchThread
。
不幸的是,一般来说,您不能替换库所使用的invokeLater
和isDispatchThread
。