RCP程序多任务调用总结

By | 2015年8月13日

方法对比表

方法名 访问UI 阻塞调用者 特点
BusyIndicator.showWhile
(Display,Runnable)
YES YES Runnable运行期间,鼠标呈忙碌状态,但是GUI会冻结。
Job NO NO 程序右下角显示Progress
UIJob YES NO 使用asyncExec在UI线程上执行,右下角不显示Progress。
WorkbenchJob YES NO 继承于UIJob,只是在shouldSchedule()、shouldRun()和performeDone()时检查workbench是否running,如果没有running则不执行操作。
Display.syncExe(Runnable) YES YES 阻塞式访问UI线程
Display.asyncExec(Runnable) YES NO 非阻塞式访问UI线程
PlatformUI.getWorkbench().
getProgressService().
busyCursorWhile(
IRunnableWithProgress)
NO YES 鼠标呈Busy状态,超过800ms,弹出Progress Dialog
PlatformUI.getWorkbench().
getProgressService().
run(fork, cancel, runnable)
NO YES 直接弹出Progress Dialog。fork要为true,否则进度条不显示;cancel为false时,cancel按钮是disable的。
PlatformUI.getWorkbench().
getProgressService().
runInUI(IRunnableContext,
runnable, rule)
YES YES GUI没有反馈,尽量不要执行时间太长
ModalContext.run
(IRunnableWithProgress,
fork, monitor, display)
NO YES 对UI线程友好,在等待执行期间,UI线程会继续响应用户的操作。当fork是true时,调用者会等待其执行完毕;当fork为false时,运行在调用者线程上。

BusyIndicator会冻结UI,谨慎长时间调用

使用BusyIndicator执行Runnable时,GUI会被冻结,鼠标呈Busy状态。如果Runnable运行时间太久,UI在此期间停止响应、刷新,会给人死机的感觉,大大降低了用户体验。这也就是为什么PlatformUI.getWorkBench().getProgressService().busyCursorWhile()在运行800毫秒后,会弹出一个Progress Dialog。

当GUI已经有progress view或者progress dialog的时候,程序就不要再使用BusyIndicator了,BusyIndicator会导致progress view和progress dialog冻结,适得其反。GUI只需要一个Runnable运行反馈就够了。

P.S.
BusyIndicator只能在可以访问UI的线程中调用,任何需要访问UI线程的方法,都会冻结UI。

UI线程等待非UI线程,使用ModalContext防止UI冻结

场景:点击Refresh按钮,刷新表格。

  • Step 1: 使用非UI线程计算数据(花10s)
  • Step 2: 拿到数据,刷新表格

Step 2需要等待Step 1执行完,我们可以使用:

  1. 不推荐)Join方法,等待非UI线程运行期间,会使UI冻结,降低用户体验。
  2. 推荐)使用ModalContext运行非UI任务,UI线程继续响应用户,当前UI线程会被加入到SWT事件队列,当ModalContext运行结束后,刷新表格,用户体验度高。

Code example:

//—> Non UI work to calculate count.
ModalContext.run(new IRunnableWithProgress() {
  @Override
  public void run(IProgressMonitor monitor) throws 
InvocationTargetException, InterruptedException { calculateCount(); } }, true, new NullProgressMonitor(), Display.getDefault()); //—> Refresh UI refreshUI();