方法对比表
方法名 | 访问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执行完,我们可以使用:
- (不推荐)Join方法,等待非UI线程运行期间,会使UI冻结,降低用户体验。
- (推荐)使用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();