SwingUtilities InvokeLater - 什么被认为是不良实践?

3
我对 SwingUtilities 的 invokeLater 方法有一个问题,想请教一下正确使用的实践方法。
首先,我想确认我的理解是否正确。据我所知,GUI 的更改必须在 EDT 上进行,因为 Swing 组件不是线程安全的。invokeLater 方法将 Runnable 作为参数,其中包含的任何内容都将在 EDT 上运行。因此,所有对 Swing 组件的调用都被放置在一种队列中,按顺序在 EDT 上执行。
那么,我的问题是:使用它的最佳实践是什么?从我看到的,至少有两种方法:
1)在 main 方法中,将所有代码,例如 GUI 创建、Controller 创建,甚至 Model 创建(假设采用 MVC 类型模式),都放置在由 invokeLater 方法调用的 Runnable 中。当然,这是假定在 Model 中执行任何长时间运行的任务都将使用 SwingWorker 执行的情况下。
2)将 GUI 创建放置在 invokeLater 中,但将 Controller 创建和 Model 创建放置在 main 方法中。然后,每当需要从 Controller 访问 Swing 组件时,您就可以将该代码放入 invokeLater 方法中以将其放置在 EDT 队列中。
哪种方法被认为是最佳实践或不良实践?如果这两种方法都不好,那么更好的方法是什么?
非常感谢您提供的任何信息。
谢谢。
2个回答

2

这确实是一个有趣的问题,而且被接受的答案并没有完全回答它。

你所提出的两种方法都可以接受,而且都能正常工作,但我相信第一种方法比第二种更好(全部在EDT上完成,如果有一些长时间运行的任务,则在SwingWorker或新线程上执行,如果它们与Swing无关)。


为什么?正如@ThomasKrägler在这里所指出的:

虽然您可以在主线程和EDT之间分配这些任务(模型、控制器和视图创建),并可能获得几毫秒的时间,直到UI首次显示,但这也会使应用程序的设计变得复杂(多线程不是一个简单的话题),并且在代码库中散布着invokeLater()调用。

请注意,EDT在初始化模型和控制器之前(从而启动视图)不需要处理任何内容。因此,您可以使用EDT来初始化它们,因为它不会对您的UI产生任何负面影响(还没有UI)。

通过这种方式,您将节省大量的invokeLater调用和可能忘记调用invokeLater而导致的错误。您的代码看起来也更加清晰。


谢谢!已经有一段时间没有使用Java了,但这是下次使用它时的绝佳信息。 - DBS

1

SwingWorker并不特殊,它只是一些常见场景的包装器。它会代表您调用invokeLater,因此您提出的两种情况实际上只是相同事物的实例。

请确保遵循以下两个规则: 1. 不要阻塞EDT 2. 在EDT上执行与Swing相关的代码


谢谢!所以当你说“在EDT上执行Swing相关代码”时,例如,在我的OP中的情况1),视图、模型和控制器都在invokeLater中实例化,因此我认为它们都在EDT上。但是,模型不会在EDT上执行其代码,它会创建一个新的SwingWorker来执行长时间运行的任务。这是不好的做法吗? - DBS
2
@DBS:不,创建一个新的SwingWorker来执行长时间运行的任务是正确的做法。 - Gilbert Le Blanc
@GilbertLeBlanc 谢谢!从我所看到的来看,除非你在EDT上运行与Swing组件无关的代码并因此导致GUI挂起之类的愚蠢行为,否则没有真正“不好”的使用方式。 - DBS
1
如果是对JComponent的方法调用,则需要在EDT上执行,否则仅在实例化时在EDT上执行。模型、视图、控制器,可能只有视图部分需要在EDT上执行。 - Charlie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接