I am trying to get a simple data-binding example to work to better understand using the JavaFX service class and possibly incorporating it into a project I am working on, however I have been unable to bind the value that shoudl be returned from the service (an Integer) to an integer in the class that calls the service.
I have checked the debugger and confirmed that the task is actually returning the value but I keep getting a null pointer exception stating that I "Cannot bind to null" for the line of code that does the binding, however, the other properties that I have binded seem to be working fine
Main Class
public class Main extends Application {
private Service<ObservableValue<Integer>> service;
@Override
public void start(Stage primaryStage){
/**********************************
* Start of Multi-Threading Logic
**********************************/
service = new EmployeeService();
ObjectProperty<Integer> size = new SimpleObjectProperty<>(0);
size.bind(service.getValue()); // Null Pointer Exception Cause
progressBar.progressProperty().bind(service.progressProperty());
progressBar.visibleProperty().bind(service.runningProperty());
progressLabel.textProperty().bind(service.messageProperty());
progressLabel.setVisible(false);
/*************************************************************
* Start Task Button Event Handler
*
* If the service state is succeeded or cancelled
* then the service must first be reset before starting
*
* if the service state is ready then start the service
*
* if the service state is something other than the above
* like running or failed, then do nothing
*************************************************************/
startTaskButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if(service.getState() == Service.State.SUCCEEDED
|| service.getState() == Service.State.CANCELLED) {
service.reset();
service.start();
}else if(service.getState() == Service.State.READY) {
service.start();
}else {
System.out.println("Not doing anything");
}
}
});
/*************************************************************
* Cancel Task Button Event Handler
*
* The service should only be canceled if it is currently
* running, else do nothing.
*************************************************************/
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
if(service.getState() == Service.State.RUNNING) {
service.cancel();
}
}
});
Service Impl Class
/*************************************************************
* Custom Service Impl class that creates the DisplayDataTask
*************************************************************/
class EmployeeService extends Service<ObservableValue<Integer>>{
@Override
protected Task<ObservableValue<Integer>> createTask() {
return new DisplayDataTask();
}
}
Task Impl Class
/*************************************************************
* Custom Task Impl class that creates a basic list
* and returns the length of the list in the call method
*************************************************************/
class DisplayDataTask extends Task<ObservableValue<Integer>> {
@Override
protected ObservableValue<Integer> call() throws Exception {
int randomNum = 71890;
Thread.sleep(5000); // Sleep for 5 seconds to simulate a task
ObjectProperty<Integer> size = new SimpleIntegerProperty(randomNum).asObject();
return size;
}
@Override
protected void cancelled() {
super.cancelled();
updateMessage("Operation Cancelled");
System.out.println("The " + this.getClass().getSimpleName() + " has been canceled.");
}
}
Service.getValue()
returns the service's current value, and before the service completes, it returns null.
You almost certainly don't want the service to return an ObservableValue<Integer>
here, you want it to return an actual Integer
. So rewrite the service as:
class EmployeeService extends Service<Integer>{
@Override
protected Task<Integer> createTask() {
return new DisplayDataTask();
}
}
with
class DisplayDataTask extends Task<Integer> {
@Override
protected Integer call() throws Exception {
int randomNum = 71890;
Thread.sleep(5000); // Sleep for 5 seconds to simulate a task
Integer size = randomNum ;
return size;
}
@Override
protected void cancelled() {
super.cancelled();
updateMessage("Operation Cancelled");
System.out.println("The " + this.getClass().getSimpleName() + " has been canceled.");
}
}
and then you can just do
size.bind(service.valueProperty());
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.