Posted on 2008-07-01 18:08
Raul Gong 閱讀(699)
評論(0) 編輯 收藏 所屬分類:
eclipse
轉(zhuǎn)載自:
http://www.javaeye.com/topic/47919 感謝原作者
在RCP中要在非UI線程中執(zhí)行UI線程的操作,最簡單的方式就是display.syncExec或者display.asyncExec,如果UI線程所需的時間較長的話,則應該使用display.asyncExec
在執(zhí)行異步線程的時候,我們一般應當繼承Job或者UIJob類:
UIJob是在UI線程中運行的,可以直接訪問窗體組件。Job是在非UI線程中運行,如果在里面想訪問窗體組件,需要通過Display.asynExec()或者synExec方式來執(zhí)行。UIJob要盡量的短,不要過多的占用UI線程的時間。
在我現(xiàn)在的系統(tǒng)中,每當UI需要和Server交互的時候,都需要檢測Server是否啟動,如果未啟動的話,嘗試啟動三次,三次不成功則拋出Exception,用MessageDialog給用戶提示,啟動成功以后,還需載入相關信息。這樣的異步線程,就只能放到Job中執(zhí)行。
然而,這樣還是遠遠不夠的,試想一下,如果點完一個MenuItem以后,過了很久才會有所反應,這種用戶體驗豈不是糟糕透了?于是我們還要提供進度條來提高用戶體驗度,在RCP中,就是如下的代碼:
- ProgressMonitorDialog progress = new ProgressMonitorDialog(null);
- progress.setCancelable(true);
- try {
- progress.run(true, true, new IRunnableWithProgress() {
- public void run(IProgressMonitor monitor)
- throws InvocationTargetException {
- doSomething();
- }
- });
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
-
- }
第二行中的progress.setCancelable(true)是為了允許客戶在長時間執(zhí)行后臺進程的時候,可以取消掉進程的執(zhí)行。這里我把實際的執(zhí)行過程Extract了出來,免得方法太長,doSomething()看起來應該是這樣子的:
- public void doSomething(IProgressMonitor monitor) {
- monitor.beginTask("Beginning...", IProgressMonitor.UNKNOWN);
- monitor.subTask("Doing first job");
- doFirstThing();
- if(monitor.isCanceled()) return;
- monitor.worked(1);
- monitor.subTask("Doing second job");
- doSecondThing();
- if(monitor.isCanceled()) return;
- monitor.worked(2);
- ......
- monitor.done();
- }
- }
這樣子當用戶點擊ProgressMonitor的Cancel按鈕時,monitor.isCanceled()就會返回true,doSomething便中止執(zhí)行。
說到這里,可能就會有疑問了,monitor.isCanceled()方法只會在doFirstThing()和doSecondThing()之間才會被觸發(fā),那么如果doFirstThing()的過程中有異常情況而導致無法返回,那點擊Cancel就根本沒有作用啊?
唔......這個就是問題的核心所在了,我不知道別人是如何解決的,在這里我只說一下我的解決方案,希望能夠起到拋磚引玉的作用:
在前面已經(jīng)提到,我使用了Job來處理異步線程,然而Job是通過調(diào)用job.schedule來執(zhí)行的,用戶無法確保job被執(zhí)行的時機以及何時結(jié)束,一般的方法是使用Listener,Observer或者某個信號量來指示Job的結(jié)束。在有些地方我用的是Observer模式,而在這種情況下,我用的是boolean變量來做指示。于是,上面的doSomething就變成了:
- public void doSomething(IProgressMonitor monitor) {
- monitor.beginTask("Beginning...", IProgressMonitor.UNKNOWN);
- monitor.subTask("Doing first job");
- job.schedule();
- while (!jobFinished) {
- if (monitor.isCanceled()) {
- logger.info("monitor is canceled");
- job.cancel();
- return;
- }
- monitor.worked(times);
- times++;
- }
- monitor.done();
- }
- }
這樣,只要while循環(huán)沒有滿足結(jié)束條件,我們就可以通過點擊Cancel按鈕來cancel掉Job。如果job中還有些東西是無法自動cancel掉的話,比如Socket通信等,我們還可以在job.cancel()前面加上一些代碼來做這樣的工作,比如job.getSocket().close()等,當然還要處理好各種Exception。
在Eclipse的Article里面,有幾篇分別講述Job和ProgressMonitor的文章,很是詳細,有興趣的朋友不妨找來看看。不過文章只是講解原理性的東西,開發(fā)中所碰到的問題,還是要靠個人的經(jīng)驗來分析解決......所以,還是多多coding,多多thinking,提高解決實際問題的能力吧:)
ProgressMonitor的Article:
http://www.eclipse.org/articles/Article-Progress-Monitors/article.html