将IProgressMonitor分成多SubMonitor可以控制每个子任务的progress。
1. 构造方法newChild
有两个重载的方法,一个参数的会调用两个参数的,SUPPRESS_BEGINTASK,表示在child monitor里调用beginTask(String, int)不会修改proress的title。
public SubMonitor newChild(int totalWork) { return newChild(totalWork, SUPPRESS_BEGINTASK); } public SubMonitor newChild(int totalWork, int suppressFlags);
2. 典型的使用
//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啥也没做。
//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。
void wrongMethod(IProgressMonitor parent) { SubMonitor progress = SubMonitor.convert(parent, 100); callMethod(progress.newChild(50), computeValue(progress.newChild(50))); }
正确做法:将方法分解,保证每次只有一个SubMonitor在被使用。
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。
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。
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); } });