2012-05-28 58 views
1

我有数百个在EDT中运行的不同功能。其中很多包括长时间运行的任务,有些包括对GUI的更改。有时用户图形用户界面会挂起,但由于图形用户界面在100%的时间内不在同一区域发生,所以很难跟踪发生这种情况的所有位置。该问题不是高优先级,因为挂起通常在窗口最小化/最大化之后开始工作,但最终需要完成。替代SwingWorker或如何在这种情况下实现它...?

经过一番研究后,我发现我可以在SwingWorker下使用doInBackground()来处理任何劳动敏感的工作方法,并在GUI绘图中使用done()。另外,我相信我可以使用SwingUtilities.invokeLater来处理恰好在doInBackground()函数中的每个GUI绘图。但是,我想避免在代码中调整数百个函数中的每一个。

有没有一种方法可以使用单个SwingWorker并将任何长时间运行的方法发送到doInBackground()函数?对于使用SwingWorker的每个错位的GUI代码多次使用invokeLater函数是而不是的一个问题,因为它不是那么频繁。

如果这是不可能的,是否有某种替代方法可以使用?谢谢。

回答

2

更新GUI的所有方法必须在EDT上调用,否则最终可能会出现一些无法解释的GUI行为(这听起来像您所看到的)。线程竞赛等。

不建议在GUI上运行长时间运行的任务,因为它们会导致GUI无响应,因此对于长时间运行的任务,SwingWorker是一个很好的解决方案(请注意,EDT自动调用进程和完成方法,因此您的工作人员可以在doInBackground中执行其长时间运行的工作,但您可以安全地更新GUI,而无需使用done方法中的SwingUtilities.invokeLater)。

正如你所提到的,你有数百种方法,并且你不想每次都调用SwingUtilities.invokeLater,你可能需要查看一个任务框架。 Swing应用程序框架是JSR-296 http://java.sun.com/developer/technicalArticles/javase/swingappfr/下的开发人员,但没有得到积极的支持,但仍然提供了一个很好的框架。 http://en.wikipedia.org/wiki/Swing_Application_Framework是一个替代框架的列表。

这听起来像你将需要在你的应用程序中做一些重要的重写。从美国东部时间以外调用GUI方法是不安全的。

+0

我想我写了部分的问题不正确。我想避免使用SwingWorker重写这些方法中的所有长时间运行的任务,并希望能够拥有一个可以使用所有方法的SwingWorker。 多次使用SwingUtilities.invokeLater不是**问题,因为它不会经常发生。 我将编辑我的帖子并修复通信错误。 –

+0

不幸的是,你不能多次重复使用同一个SwingWorker。 –

+0

好的,我将不得不单独为每种方法添加SwingWorkers。谢谢! –

1

我不明白你的问题是可能的。在执行之前,Swing无法知道什么可以称为“长时间运行”的方法调用。如果该方法已被执行(在EDT上),Swing不能简单地将其提取并将其移至新线程。即使你会指出哪些方法调用应该在后台线程中运行,将其拉下来也很难。我认为在Java中实现这一点的唯一方法是使用AOP(您可以拦截方法调用)。但是实施AOP会更难,然后重新实现您现有的应用程序来使用SwingWorkers。

听起来你的Swing应用程序的体系结构已经坏了。长时间运行的任务不得在EDT上执行。我很抱歉,但我认为你只需要忍受这一点。如果你想让你的应用程序感觉灵敏,反应迅速并具有可预测的行为,你将不得不通过将长时间运行的代码放在后台线程中来解决这个问题。

如果您的应用程序使用了很多后台任务,您可能需要使用优秀的Swing Task API。否则,你会发现自己在一个SwingWorker意大利面条相当快。

对于出现这种情况是在doInBackground()

你不能叫摆动拉丝,更新等,在“doInBackground()方法的方法每个GUI描绘(好其实你可以,但你不能那样做)。这是因为这是从EDT执行的方法。 GUI绘图和组件更新只能在SwingWorker的'done()'方法中调用。

+0

嗯,好像我将不得不坚持将SwingWorkers添加到一切。我希望会有另一种方式。谢谢! –

+0

我同意这个答案。当你正在改造的东西考虑做你自己的SwingWorker的扩展。例如,我有一个Busiable接口,我的应用程序的各个组件实现了将忙碌的动画放在GUI的任何部分的顶部。这通常使用JLayer/JXLayer。在AppSwingWorker内部,它启动繁忙的动画并在doInBackground完成时停止它。我的AppSwingWorker所做的另一个有用的事情是在doInBackground()冒泡过程中将done()和get()作为任何异常进行包装,然后它具有记录错误的默认行为。 – Jim

+1

另一件需要了解的事情是Java 7 [SecondaryLoop](http://docs.oracle.com/javase/7/docs/api/java/awt/SecondaryLoop.html)。目前没有太多的文档,但它可能对你有用。 – Jim