我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”中,您可以将要执行的代码作为参数提供给源事件或线程安全副本其中(我猜你有一个源事件,无论它的类型是什么)。
您是否将匿名Runnables 传递给invokeLater()?
如果是,我建议将它们替换为非匿名类,这将添加几行代码,但至少会给您一定程度的可追溯性(例如:)TableUpdateFromQuery。如果您仅从应用程序中的一个位置调用特定类型的更新,则此方法效果最佳。它还引导您走上“后台活动”的道路,可以在 UI 之外进行测试。
如果您invokeLater经常调用,您可能需要考虑简化线程。
invokeLater有效地使用了可变静态,因此是最纯粹的邪恶。如果您从调用切换EventQueue.invokeLater到使用带有invokeLater和的接口,测试和更多操作将变得更加容易isDispatchThread。
不幸的是,一般来说,您不能替换库所使用的invokeLater和isDispatchThread。