当前位置: 动力学知识库 > 问答 > 编程问答 >

java - How to obtain Task instance from Service handler method in JavaFX

问题描述:

I have a JavaFX service in which Task is created to do some work:

public class MyService extends Service<Void> {

@Override

protected Task<Void> createTask() {

return new Task<Void>() {

@Override

protected Void call() throws Exception {

// do some work

return null;

}

};

}

}

I also have a handler for success:

myService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {

@Override

public void handle( final WorkerStateEvent event ) {

// check what Task has finished

}

});

As it is possible to run the service more than once concurrently, I wan't to be able to distinguish from success handler what instance of Task has finished. Looking into the doc, I could not find any way, how to do it.

My idea was to extend Task to contain some id, e.g. integer, and then to be able obtain that instance from event handler.

Any idea, how to achieve such behavior would be much welcome.

Thanks in advance.

网友答案:

First, I would question why you needed to do this. The task itself should encapsulate all the logic that is specific to its own particular instance. It feels like there should be a better solution to whatever it is you're trying to achieve.

So the most obvious way to do this would be to have your Task return the value you are interested in. E.g.

public class MyService extends Service<Integer> {

    private int nextId = 0 ;

    @Override
    protected Task<Integer> createTask() {
        private final int id = ++nextId ;
        return new Task<Integer>() {
            @Override
            protected Integer call() throws Exception {
                // do some work
                return id;
            }
        };
    }
}

Then

Service<Integer> service = new MyService();
service.setOnSucceeded(e -> System.out.println("Task " + service.getValue() + " finished"));

Note also that you can override the succeeded() method of Task (as well as registering a handler with the service). So you can do

public class MyService extends Service<Void> {

    private int nextId = 0;

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {

            final int id = ++nextId ;

            @Override
            protected Void call() throws Exception {
                // do some work
                return null;
            }

            @Override
            protected void succeeded() {
                super.succeeded();
                System.out.println("Task "+id+" completed successfully");
            }
        };
    }
}

The succeeded() method is invoked on the FX Application Thread.

If you really want to manage this via the service, you could just keep a reference to the latest task that was started in the service implementation. Since a Service can only run one task at a time, when the service enters the SUCCEEDED state, this is guaranteed to be the task that just completed. For example:

public class MyService extends Service<Void> {

    private Task<Void> mostRecentTask ;

    @Override
    protected Task<Void> createTask() {
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                // do some work
                return null;
            }
        };
        task.setOnRunning(e -> mostRecentTask = task);
        return task ;
    }

    public Task<Void> getMostRecentTask() {
        return mostRecentTask ;
    }
}

Then

MyService service = new MyService();
service.setOnSucceeded(e -> {
    Task<Void> completedTask = service.getMostRecentTask();
    // ...
});

But, as I said before, it feels like there should be a more elegant way to achieve whatever it is you're trying to do at a more fundamental level.

分享给朋友:
您可能感兴趣的文章:
随机阅读: