Time for action – using null progress monitors and submonitors

When a method uses progress monitors extensively, it is inelegant to keep checking whether the monitor is null or not. Instead, the progress monitor can be replaced with a NullProgressMonitor, which acts as a no-op for all monitor calls.

  1. Update the checkDozen() method to use a NullProgressMonitor, if null is passed.
    private void checkDozen(IProgressMonitor monitor) {
      if(monitor == null)
        monitor = new NullProgressMonitor();

    This allows the remainder of the method to run without modification, and saves any NullPointerExceptions that may result.

  2. A similar result is obtained for both the NullProgressMonitor and SubProgressMonitor with a wrapper/factory class called SubMonitor. This provides factory methods to wrap the monitor and creates child progress monitors.
    protected IStatus run(IProgressMonitor monitor) {
      try {
        SubMonitor subMonitor = 
          SubMonitor.convert(monitor,"Preparing", 5000);
        for (int i = 0; i < 50 && !subMonitor.isCanceled(); i++) {
          if (i == 10) {
            subMonitor.subTask("Doing something");
          } else if (i == 25) {
            subMonitor.subTask("Doing something else");
          } else if (i == 40) {
            subMonitor.subTask("Nearly there");
          } else if (i == 12) {
            checkDozen(subMonitor.newChild(100));
            continue;
          }
          Thread.sleep(100);
          subMonitor.worked(100);
        }
      } catch (InterruptedException e) {
      } finally {
        if(monitor != null)
          monitor.done();
      }
    }
  3. Running the code has the same effect as the previous one, but it's more efficient. Note that the subMonitor object is used everywhere in the method until the end, where monitor is used to invoke done(). Since monitor may be null, it is guarded with a test.

What just happened?

The NullProgressMonitor was replaced with a SubProgressMonitor with a SubMonitor. To convert an arbitrary IProgessMonitor into a SubMonitor, use the convert() factory method. This has the advantage of testing for null (and using an embedded NullProgressMonitor if necessary) as well as facilitating the construction of SubProgressMonitor instances with the newChild() call.

Note that the contract of SubMonitor requires the caller to invoke done() on the underlying progress monitor at the end of the method, so it gives an error when it's done an assignment such as monitor = SubMonitor.convert(monitor) in code.

Since the isCancelled() check will ultimately call the parent monitor, it doesn't strictly matter whether it is called on the submonitor or the parent monitor. However, if the parent monitor is null, invoking it on the parent will result in a NullPointerException, whereas the SubProgressMonitor will never be null.

In situations where there will be lots of recursive tasks, the SubProgessMonitor will handle nesting better than instantiating a SubProgressMonitor each time. That's because the implementation of the newChild() method doesn't necessarily need to create a new SubMonitor instance each time; it can keep track of how many times it has been called recursively.

The SubMonitor also has a setWorkRemaining() call, which can be used to reset the amount of work for the outstanding progress monitor. This can be useful if the job doesn't know at the start how much work there is to be done, but it does become known later in the process.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset