2

With JavaFX UI controller event I want to pause the background Service, service which start with that UI controller (as show on following code).

I have found a similar post JavaFX2: Can I pause a background Task / Service. But with that post it will give solution to pause a Service with it's own events, not for events fire with external UI Controller.

Actually in this case it seems I have to set the Service's internal State to make it pause but Worker Interface didn't contains such a Sate. As a example we can force to fail a Service, with it's FAILED State etc.

Thanks.

UI Controller class

public class CommandController implements Initializable {

 private CommandService commandService;
 private ExecutorService sequentialServiceExecutor;
 private List<IOCommandService> servicePool = new ArrayList<>();

 @Override
 public void initialize(URL location, Resources resources) {

   doProceedInitialSteps(); 
 }

 private void doProceedInitialSteps() { 

   // Select available IOCommands 
   List<IOCommand> commandList = commandService.getCommands();

   // Initialised ExecutorService on sequential manner
   sequentialServiceExecutor = Executors.newFixedThreadPool(
                1,
                new ServiceThreadFactory()
   );

   for (final IOCommand command : commandList) { 

        IOCommandService service = new IOCommandService(command, this);

        service.setExecutor(sequentialServiceExecutor);

        service.setOnRunning(new EventHandler<IOCommand>() { }

        service.setOnSucceeded(new EventHandler<IOCommand>() { }

        service.setOnFailed(new EventHandler<IOCommand>() { }

        service.start();

        servicePool.add(service);       
   }

 }

 @FXML
 public void onCancel() {

   // TODO: Need to pause current executing IOCommandService until receive the user response from the DialogBox

   // Unless pause current executing IOCommandService, that will over lap this dialog box with IOCommandService related dialog boxes etc  

   Dialogs.DialogResponse response = Dialogs.showWarningDialog();

   if(response.toString.equals("OK") {

   }
 }

}

Service class

public class IOCommandService extends Service<IOCommand> {

  private IOCommand command;
  private CommandController controller;

  public IOCommandService (IOCommand command, CommandController controller) {
     this.command = command;
     this.controller = controller;
  }

  @Override
  protected Task<IOCommand> createTask() {

    return new Task<IOCommand>() {

        @Override
        protected Integer call() throws Exception {

         // Execute the IO command by,
         // 1) updating some UI components (label, images etc) on CommandController
         // 2) make enable popup some Dialog boxes for get user response  

         return command;            
        }
    }
  }    
}
Community
  • 1
  • 1
Channa
  • 4,963
  • 14
  • 65
  • 97

1 Answers1

3

Hej Channa,

here is an example how you can "pause" your Service and after closing the Dialog resume it.

Here is the FXML ;)

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="de.professional_webworkx.stopservice.FXMLController">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
    </children>
</AnchorPane>

MainApplication

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class MainApp extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml"));

        Scene scene = new Scene(root);

        stage.setTitle("JavaFX and Concurrency");
        stage.setScene(scene);
        stage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }

}

The Controller

import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

public class FXMLController implements Initializable {

    @FXML
    private Label label;
    private MyService ms;
    @FXML
    private void handleButtonAction(ActionEvent event) {
        onCancel();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        ms = new MyService();
        Platform.runLater(() -> {
            ms.start();
        });
    }    

    public void onCancel() {

        if(ms.getState().equals(Worker.State.RUNNING)) {
            ms.cancel();
        }
        Scene s = new Scene(new Label("Dialog"), 640, 480);
        Stage dialog = new Stage();
        dialog.setScene(s);
        dialog.showAndWait();

        if(!dialog.isShowing()) {
            ms.resume();
        }


    }
}

And the MyService class

I run a for Loop on the Console and print out the Numbers. If i call the pause() Method of MyService i cancel() it and restart() it on the call of resume() Method. The Thread.sleep(2000L); i only added to simulate a long running Task.

import javafx.concurrent.ScheduledService;
import javafx.concurrent.Service;
import javafx.concurrent.Task;

/**
 *
 * @author Patrick Ott
 * @version 1.0
 */
public class MyService extends ScheduledService<Void> {

    Task<Void> task;
    int n = 1000000000;
    @Override
    protected Task<Void> createTask() {
        return new Task() {

            @Override
            protected Object call() throws Exception {
                for (int i = 0; i < n; i++) {
                    System.out.println("Halllo " + n);
                    Thread.sleep(2000);
                    n--;
                }
                return null;
            }
        };
    }

    public void pause() {
        this.cancel();
    }

    public void resume() {
        System.out.println("n="+n);
        this.restart();
    }
}

Patrick

ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
Patrick
  • 4,532
  • 2
  • 26
  • 32
  • Hi Patrick! Many thanks for the feedback. But with this logic it seems we can not pause the Service. That mean "cancel()" method will not pause the service, it will terminates execution of Service. And also "restart()" method will cancels any currently running Services, and restarts Service from the beginning. When it get all together it seems Terminate the service and Start from the very begging. – Channa Aug 01 '14 at 02:52
  • @Channa maybe you can edit your Question and add the Logic you run in your Service and also give a hint how many Services you'll have to run at the same time. It is an interesting problem.. – Patrick Aug 01 '14 at 06:49
  • Hi Patrick! Thanks for the feedback. I have just update the Question. Thanks. – Channa Aug 01 '14 at 08:03