简体   繁体   中英

JavaFX Why The Task returns Null?

I'm trying to learn Threads and Tasks for days now ... but still can't implement it in my app ... help plz.

I want to run all Database operations in a background thread other than the application thread. I have a class that manages the Database queries ... in this class i surrounded the executeQuery statement with a task:

public class Database {

ResultSet rs;

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {       
    Task<ResultSet> task = new Task<ResultSet>() {
     @Override protected ResultSet call() throws Exception {
             if (isCancelled()) {
             }                    

                 ResultSet execRs = stmnt.executeQuery();
                 return execRs;
         }
     };     
    task.run();
    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
        @Override
        public void handle(WorkerStateEvent event) {                
             rs = task.getValue();
        }            
    });
    return rs;
}
// remaining Code
}

As you can see the method should return a ResultSet but when i call this from another place it raise a null pointer ... the result set returned by this method is null.

So what did i do wrong here?

Update #1 @James_D Thank you for this great link ... i think i finally understand the concept ... but still have a small problem with implementing it ... for example in my authentication method after the user is authenticated i want to check if that user has an open shift ... so following your link i changed the method to this:

    private boolean isShiftOpen(int userId, int branchId, int comId) throws SQLException, ClassNotFoundException {
//        final boolean success = false; 
        Task<Shift> task = new Task<Shift>(){
            @Override
            protected Shift call() throws Exception {
                return ShiftDAO.getShift(userId, branchId, comId);
            }            
        };
        task.setOnFailed(e -> {
            System.out.println("isShiftOpenTask Faild!!");
            success = false;
        });
        task.setOnSucceeded(e -> {
            System.out.println("isShiftOpenTask Succeeded!!");
            Shift shift1 = task.getValue();
            System.out.println("User Open Shift Exists ... returning true");
            SessionBean.setShiftId(shift1.getShiftId());
            SessionBean.setUserId(shift1.getUserId());
            SessionBean.setUserBranch(branchId);
            success = true;
        });
        exec.execute(task);
        return success;

    }

I have two problems: 1- The exec.execute(task) raise a nullpoint exception. 2- I wanted to use a boolean variable returned by this method ... the only way i could access such a variable is to define it outside the method ... but then if i want to use another method like this one i must declare another boolean variable for it to ... does this sound right to you?

Thank you for your time Gado

You call

task.run();

which executes the task on the current thread , ie that statement will not complete until the task finishes. Then you call

task.setOnSucceeded(...);

which essentially says "when the task succeeds, set the instance variable rs to the result of the task. However, by the time you call this, the task has already succeeded (or possibly failed), so there is no way for the handler to be invoked.

You could fix the null result by reversing the order of these calls, ie do

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {       
    Task<ResultSet> task = new Task<ResultSet>() {
     @Override protected ResultSet call() throws Exception {
             if (isCancelled()) {
             }                    

                 ResultSet execRs = stmnt.executeQuery();
                 return execRs;
         }
     };     
    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){
        @Override
        public void handle(WorkerStateEvent event) {                
             rs = task.getValue();
        }            
    });
    task.run();
    return rs;
}

However, since you are executing the task on the current thread, it's not really clear what the point of using a task at all is: you may as well just execute the database query directly in your execQuery method and return the result directly. In other words, the above code is equivalent to

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {       

     rs = stmnt.executeQuery();
     return rs;

}

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