2012-05-28 99 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