简体   繁体   中英

Null Pointer Exception when Data-Binding a value from a Service in JavaFX

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM