我討論的進(jìn)度條主要是JFace的進(jìn)度條,RCP已經(jīng)提供了完善的Job組件,為什么還要用JFace的進(jìn)度條呢?原因是我要在登陸界面上做進(jìn)度處理,也就是使用Eclipse3.3提供的AbstractSplashHandler特性,可以將原有的啟動畫面替換成為一個登陸界面,啟動這個登陸界面時,Eclipse的Platform此時還沒有啟動,所以不能使用RCP本身的Job組件了。
由于是一個檢測服務(wù)器是否聯(lián)通的測試,所以并不知道測試的真實(shí)時間,所以就是要使用“傻瓜進(jìn)度條”了,也就是反復(fù)走的進(jìn)度條陳剛的代碼如下:
button.addSelectionListener(new SelectionAdapter() { private boolean stopFlag;// 停止標(biāo)志 private void go() { for (int i = 0; i < 10; i++) {// 循環(huán)10次,每次間隔一秒 System.out.println("第" + (i + 1) + "個任務(wù)執(zhí)行完畢"); if (stopFlag) {// 監(jiān)控是否要讓停止后臺任務(wù) System.out.println("被中斷了"); return; } try { Thread.sleep(1000); } catch (Throwable t) {} } stopFlag = true;// 執(zhí)行完畢后把標(biāo)志位設(shè)為停止,好通知給進(jìn)度框 System.out.println("全部任務(wù)執(zhí)行完畢"); } public void widgetSelected(SelectionEvent e) { stopFlag = false;// 每次都設(shè)初值為false new Thread() {// 把后臺任務(wù)放到一個新開線程里執(zhí)行 public void run() { go(); } }.start(); showProgressDialog();// 打開一個進(jìn)度框 } private void showProgressDialog() { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { monitor.beginTask("正在執(zhí)行中......", 30); int i = 0; while (true) { // 監(jiān)聽是否單擊了進(jìn)度框的“取消”按鈕,stopFlag則是監(jiān)聽后臺任務(wù)是否停止 if (monitor.isCanceled() || stopFlag) { stopFlag = true; // 單擊了“取消”按鈕要設(shè)標(biāo)志位為停止,好通知后臺任務(wù)中斷執(zhí)行 break;// 中斷處理 } // i到30后清零。并將進(jìn)度條重新來過 if ((++i) == 30) { i = 0; monitor.beginTask("正在執(zhí)行中......", 30); } // 進(jìn)度條每前進(jìn)一步體息一會,不用太長或太短,時間可任意設(shè)。 try { Thread.sleep(99); } catch (Throwable t) {} monitor.worked(1);// 進(jìn)度條前進(jìn)一步 } monitor.done();// 進(jìn)度條前進(jìn)到完成 } }; try { new ProgressMonitorDialog(s).run(true, true, runnable); } catch (Exception e) { e.printStackTrace(); } } }); |
主要是使用兩個線程交替使用,第一個線程處理業(yè)務(wù),第二個線程監(jiān)控第一個線程查看它是否結(jié)束,如果結(jié)束或者被點(diǎn)擊cancele則停止進(jìn)度條的進(jìn)程,如果一直沒有關(guān)閉的指令,則反復(fù)開始---累加---結(jié)束---開始---累加---結(jié)束。
我們幾乎是把陳剛的代碼原原本本的抄襲了一下,僅僅是替換了go()中的內(nèi)容,但是發(fā)現(xiàn)一個問題
new ProgressMonitorDialog(s).run(true, true, runnable);
使用此句的話,JFace的線程永遠(yuǎn)不會啟動;
替換為
new ProgressMonitorDialog(s).run(false, true, runnable);
使用此句的話,JFace的線程可以啟動,運(yùn)行正常,但是cancele不能響應(yīng),UI界面完全卡死!
第一個參數(shù)的名字fork~乍看去,什么意思都沒有,但是看看API才發(fā)現(xiàn)內(nèi)藏很大的玄機(jī),如果為true則此線程為一個非UI線程,大家知道非UI線程是不會阻塞UI的;如果為false則此線程為一個UI線程,大家也知道UI線程如果使用不當(dāng)很容易阻塞UI的。
關(guān)鍵的問題是我們和陳剛的代碼幾乎一摸一樣他的進(jìn)度條就啟動,我的進(jìn)度條就不啟動!為什么?(這點(diǎn)至今不明白!)
詳查API發(fā)現(xiàn)如果fork為false的時候還是另有洞天的:
This implementation of IRunnableContext#run(boolean, boolean, IRunnableWithProgress) runs the given IRunnableWithProgress using the progress monitor for this progress dialog and blocks until the runnable has been run, regardless of the value of fork . The dialog is opened before the runnable is run, and closed after it completes. It is recommended that fork is set to true in most cases. If fork is set to false , the runnable will run in the UI thread and it is the runnable's responsibility to call Display.readAndDispatch() to ensure UI responsiveness. |
API中說的很明白,如果fork為false時需要在線程中調(diào)用Display.readAndDispatch()方法,以避免UI被阻塞!
大家如果在JFace的開發(fā)中如果使用了進(jìn)度條,發(fā)現(xiàn)UI被阻塞的話,就想想我哦!!!呵呵只用在進(jìn)程中調(diào)用一下Display.readAndDispatch()就解決了!
客戶虐我千百遍,我待客戶如初戀!