Search code examples
javajava-threads

How to update progress from within a custom class


I need to update the progress from a custom class inside a worker/task thread. How do I do this?

public Task createWorker() {
    Task task = new Task() {

        @Override
        protected Object call() throws Exception {
            DocumentProcessor dp = new DocumentProcessor();
            dp.proces(this);
        }

        public void notifyTask(String _msg, long _stepNumber, long _totalSteps ){
            updateMessage(_msg);
            updateProgress(_stepNumber, _totalSteps);
        }
    };
}

class:

public class DocumentProcessor {
    public void proces(Task _task){
         // Step 1
         _task.notifyTask("Step 1 done", 1 ,2); // ERROR: no function with that name

         // Step 2
         _task.notifyTask("Step 2 done", 2 ,2);

    }
}

invoke

    Task worker = createWorker();
    new Thread(worker).start();

The notifyTask function is not available.


Solution

  • The notifyTask method is not available because it's not included in the Task class, but defined in your (anonymous) subclass.

    You can for example create a named subclass and pass that to the DocumentProcessor.

    public class NotifiableTask extends Task {
        @Override
        protected Object call() throws Exception {
            DocumentProcessor dp = new DocumentProcessor();
            dp.proces(this);
        }
    
        public void notifyTask(String _msg, long _stepNumber, long _totalSteps ){
           updateMessage(_msg);
           updateProgress(_stepNumber, _totalSteps);
       }
    }
    public Task createWorker() {
       return new NotifiableTask();
    }
    
    public class DocumentProcessor {
        public void proces(NotifiableTask _task){
           // Step 1
           _task.notifyTask("Step 1 done", 1 ,2); // function is now available because it's defined in NotifiableTask
           // Step 2
           _task.notifyTask("Step 2 done", 2 ,2);
    
        }
    }
    
    Task worker = createWorker();
    new Thread(worker).start();
    

    You can also define an interface and have your class implement that for looser coupling.

    public interface Notifiable {
        void notifyTask(String _msg, long _stepNumber, long _totalSteps);
    }
    
    public class NotifiableTask extends Task implements Notifiable {
        // implement Task's call()
        @Override
        protected Object call() throws Exception {
            DocumentProcessor dp = new DocumentProcessor();
            dp.proces(this);
        }
    
        // implement Notifiable's notifyTask
        public void notifyTask(String _msg, long _stepNumber, long _totalSteps ){
           updateMessage(_msg);
           updateProgress(_stepNumber, _totalSteps);
       }
    }
    public Task createWorker() {
       return new NotifiableTask();
    }
    
    public class DocumentProcessor {
        // we don't need Task's call() method here, so pass the Notifiable only
        public void proces(Notifiable _task){
           // Step 1
           _task.notifyTask("Step 1 done", 1 ,2); // function is now available because it's declared in Notifiable
           // Step 2
           _task.notifyTask("Step 2 done", 2 ,2);
    
        }
    }
    
    Task worker = createWorker();
    new Thread(worker).start();
    

    You'll probably need to declare NotifiableTask as an inner class of wherever you currently define the createTask method because it needs to call its other methods (updateMessage() and updateProgress()) during notifyTask(). In fact, since the task itself only delegates this call, you might as well declare the interface in the outer class and perform the update there; but this depends on the context and is hard to tell since you obviously only provided a minimized example.