詳解SwingWorker與Swing程序
某些人一拍腦袋的事,讓我有機會跟Swing干上了,因為項目組沒人用這玩意整過這東西,那就只能我硬著頭皮上了!有時候人是要有點壓力才行的。
***階段的開發:
準備階段:工具的選擇。用了Netbeans 6,試用了下,感覺畫界面還比較容易,但是生成的代碼很長,剛開始對Swing很陌生 ,看著netbeans 生成代碼很頭痛,感覺不是我想要的東西,然后放棄了。然后是VE,因為也只是倒騰了下,沒細看。***選擇了Jigloo ,但是用了之后才知道他生成的代碼也很惡劣......
開發階段:別熟悉swing 邊開發,其中遇到亂七八遭事情一堆,但是因為這個軟件的功能是比較簡單的,***終于是拿了出來,雖然BUG一堆,但是也算是我的***swing作品,客戶感覺效果很不理想(有軟件設計方面的,也有技術運用方面的),也就有了下面繼續開發的經歷了。
主要技術方面問題是,線程的亂用造成死鎖,經常造成莫名的假死。
第二階段的開發:
因為***階段的開發比較痛苦,所以決定換個語言開發。因為最近RIA比較熱,RIA里面的adoble的air也算比較熱門的,UI給人感覺很華麗,也自己嘗試做過一些DEMO。項目中用的webservice,加密解密操作,文件上傳下載都有解決的辦法,但是要命的是這個項目中要調用外部程序,air在這方面比較脆弱,google了一把 as 的 fscommand 能調用其他程序,但是 air 竟然不支持這個,后來還是塌塌實實用SWING 吧。
然后又試用了一把VE,感覺現在比上次我用的時候好多了,后來就把Jigloo換 VE了。
擺在眼前的就是如何運用好線程了。又google了一把,找到了swingworker 這個東西拉。從Java SE 6開始引進的SwingWorker能幫你輕松的編寫多線程Swing程序,改善你Swing程序的結構,提高界面響應的靈活性,這正是我要的東西。
一個Swing程序中一般有下面三種類型的線程:
◆初始化線程(Initial Thread)
◆UI事件調度線程(EDT)
◆任務線程(Worker Thread)
Swing程序只有一個用EDT,該線程負責GUI組件的繪制和更新,通過調用程序的事件處理器來響應用戶交互。所有事件處理都是在EDT上進行的,程序同UI組件和其基本數據模型的交互只允許在EDT上進行,所有運行在EDT上的任務應該盡快完成,以便UI能及時響應用戶輸入。
Swing編程時應該注意以下幾點:
1.從其他線程訪問UI組件及其事件處理器會導致界面更新和繪制錯誤。
2.在EDT上執行耗時任務會使程序失去響應,這會使GUI事件阻塞在隊列中得不到處理。
3.應使用獨立的任務線程來執行耗時計算或輸入輸出密集型任務,比如同數據庫通信、訪問網站資源、讀寫大樹據量的文件。
而我***階段開發的正是由于沒有注意到這點導致整個程序效果不佳。程序中有個事件處理都要訪問Web服務,這些服務通常要許多秒后才能響應,在此期間,如果程序在EDT上進行Web服務交互,用戶就不能取消搜索或者同界面交互,像這兩種都不應該在EDT上運行。
顯示了在A和B點之間,EDT不能處理UI事件,AB兩點之間代表了程序訪Web服務的IO操作時間:
javax.swing.SwingWorker類是Java SE 6中新出現的類,使用SwingWorker,程序能啟動一個任務線程來異步查詢,并馬上返回EDT線程。顯示了使用SwingWorker后,事件處理立即返回,允許EDT繼續執行后續的UI事件。原先就是都放在EDT上了,效果勉強也就難免了。而使用Swingworker啟動一個任務線程就可以靈活響應界面。
下面講講他的用法:
SwingWorker的定義如下:public abstract class SwingWorker
SwingWorker是抽象類,因此必須繼承它才能執行所需的特定任務。注意該類有兩個類型參數:T及V。T是doInBackground和get方法的返回類型,V是publish和process方法要處理的數據類型。
SwingWorker實現以下接口方法:
◆boolean cancel(boolean mayInterruptIfRunning)
◆T get()
◆T get(long timeout, TimeUnit unit)
◆boolean isCancelled()
◆boolean isDone()
SwingWorker實現了所有的接口方法,實際上你僅需要實現以下SwingWorker的抽象方法:protected T doInBackground() throws Exception
doInBackground方法作為任務線程的一部分執行,它負責完成線程的基本任務,并以返回值來作為線程的執行結果。繼承類須覆蓋該方法并確保包含或代理任務線程的基本任務。不要直接調用該方法,應使用任務對象的execute方法來調度執行。
在獲得執行結果后應使用SwingWorker 的get方法獲取doInBackground方法的結果。可以在EDT上調用get方法,但該方法將一直處于阻塞狀態,直到任務線程完成。***只有在知道結果時才調用get方法,這樣用戶便不用等待。為防止阻塞,可以使用isDone方法來檢驗doInBackground是否完成。另外調用方法 get(long timeout, TimeUnit unit)將會一直阻塞直到任務線程結束或超時。獲取任務結果的***地方是在done方法內:protected void done()
在doInBackground方法完成之后,SwingWorker調用done方法。如果任務需要在完成后使用線程結果更新GUI組件或者做些清理工作,可覆蓋done方法來完成它們。這兒是調用get方法的***地方,因為此時已知道線程任務完成了,SwingWorker在EDT上激活done方法,因此可以在此方法內安全地和任何GUI組件交互。
沒必要等到線程完成就可以獲得中間結果。中間結果是任務線程在產生***結果之前就能產生的數據。當任務線程執行時,它可以發布類型為V的中間結果,覆蓋process方法來處理中間結果。后文還將提供這些方法的更多詳細信息。當屬性改變時,SwingWorker實例能通知處理器,SwingWorker有兩個重要的屬性:狀態和進程。任務線程有幾種狀態,以下面SwingWorker.StateValue枚舉值來表示:
◆PENDING
◆STARTED
◆DONE
任務線程一創建就處于PENDING狀態,當doInBackground方法開始時,任務線程就進入STARTED狀態,當doInBackground方法完成后,任務線程就處于DONE狀態,隨著線程進入各個階段,SwingWorker超類自動設置這些狀態值。你可以添加處理器,當這些屬性發生變化來接收通知。
***,任務對象有一個進度屬性,隨著任務進展時,可以將這個屬性從0更新到100標識任務進度,當該屬性發生變化時,任務通知處理器進行處理。
我的使用感覺就是,象I/O操作,數據操作,網絡操作等耗時的操作放到 doInBackground()中處理,任務執行中而非任務結束時發布數據,要調用publish方法.
publish方法時,SwingWorker類調度process方法。有意思的是process方法是在EDT上面執行,這意味著可以同Swing組件和其模型直接交互。可以實現你在處理任務時,給個進度條提示。
【編輯推薦】

















