将IProgressMonitor分成多SubMonitor可以控制每个子任务的progress。
1. 构造方法newChild
有两个重载的方法,一个参数的会调用两个参数的,SUPPRESS_BEGINTASK,表示在child monitor里调用beginTask(String, int)不会修改proress的title。
1 2 3 4 5 | public SubMonitor newChild( int totalWork) { return newChild(totalWork, SUPPRESS_BEGINTASK); } public SubMonitor newChild( int totalWork, int suppressFlags); |
2. 典型的使用
1 2 3 4 5 6 | //Example 1: Typical usage of newChild void myMethod(IProgressMonitor parent) { SubMonitor progress = SubMonitor.convert(parent, 100 ); doSomething(progress.newChild( 50 )); doSomethingElse(progress.newChild( 50 )); } |
3. child可以不执行worked和done
创建children可以是progress更加平滑,child monitor可以不用调用worked方法和done方法。创建新child时,会使前一个child自动完成,即使前一个child啥也没做。
01 02 03 04 05 06 07 08 09 10 11 12 13 | //Example 2: Demonstrates the function of active children. Creating children // is sufficient to smoothly report progress, even if worked(...) and done() // are never called. void myMethod(IProgressMonitor parent) { SubMonitor progress = SubMonitor.convert(parent, 100 ); for ( int i = 0 ; i < 100 ; i++) { // Creating the next child monitor will clean up the previous one, // causing progress to be reported smoothly even if we don't do anything // with the monitors we create progress.newChild( 1 ); } } |
4. child不能并行,只能一个一个执行
错误例子:因为只有一个SubMointor是active的,其它的不会report任何progress。
1 2 3 4 | void wrongMethod(IProgressMonitor parent) { SubMonitor progress = SubMonitor.convert(parent, 100 ); callMethod(progress.newChild( 50 ), computeValue(progress.newChild( 50 ))); } |
正确做法:将方法分解,保证每次只有一个SubMonitor在被使用。
1 2 3 4 5 | void rightMethod(IProgressMonitor parent) { SubMonitor progress = SubMonitor.convert(parent, 100 ); Object someValue = computeValue(progress.newChild( 50 )); callMethod(progress.newChild( 50 ), someValue); } |
5. 一个完整的例子
参数SubMonitor.SUPPRESS_NONE使得生成的child可以修改progress title和sub title,否则得调用setTaskName(String)修改progress title。生成的child也可以设置工作量,调用worked方法和done方法逐步影响整体的progress。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | SubMonitor subMonitor = SubMonitor.convert(monitor, "Start main work..." , 100 ); subMonitor.subTask( "Sub task description..." ); Thread.sleep( 2000 ); SubMonitor newChild1 = subMonitor.newChild( 50 , SubMonitor.SUPPRESS_NONE); newChild1.beginTask( "Retrieveing data 1..." , 100 ); newChild1.subTask( "Sub task data 1..." ); //Do something... Thread.sleep( 2000 ); SubMonitor newChild2 = subMonitor.newChild( 1 , SubMonitor.SUPPRESS_NONE); newChild2.beginTask( "Retrieveing data 2..." , 100 ); newChild2.subTask( "Sub task data 2..." ); //Do something... Thread.sleep( 2000 ); |
6. 最佳实践
- SubMonitor.convert(IProgressMonitor, String, int):设置Title和work count。
- Child->subTask(String)仅需设置sub title,无需worked和done。
- 使用split代替newChild,无需check cancelled,否则newChild时应当判断是否cancelled。
注:
SubMonitor->split(…)是Eclipse 4.6加入的,用法和newChild完全一样,唯一的区别是:当用户点击cancel时,split方法会抛出OperationCanceledException。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private void runProgress(IRunnableWithProgress runnableWithProgress) { try { PlatformUI.getWorkbench().getProgressService().run( true , true , runnableWithProgress); } catch (InvocationTargetException | InterruptedException e) { LoggerFactory.getLogger(View. class ).info(e::getMessage); } } runProgress(monitor -> { try { SubMonitor subMonitor = SubMonitor.convert(monitor, "Start main work..." , 100 ); Thread.sleep( 2000 ); SubMonitor newChild1 = subMonitor.split( 50 ); newChild1.subTask( "Retrieveing data 1..." ); //Do something... Thread.sleep( 2000 ); SubMonitor newChild2 = subMonitor.split( 50 ); newChild2.subTask( "Retrieveing data 2..." ); //Do something... Thread.sleep( 2000 ); } catch (OperationCanceledException e) { // Progress is cancelled. LoggerFactory.getLogger(View. class ).info(e::getMessage); } }); |