JavaFX任务等待另一个任务完成

时间:2018-02-04 13:00:22

标签: multithreading javafx concurrency

我很有新意,而且我已经好几次撞墙了。 代码几乎描述了一切,但只是为了澄清:用户按下按钮,应用程序向db发送查询,同时statusLabel设置为:
Veryfing。
200ms
非常...... 200ms
非常...... 200ms
查询结果

我设法实现了这一点,但现在,我需要在另一个类中使用查询结果(如果成功,则打开另一个窗口),但它永远不会。我得出结论,它只是在Task完成之前检查结果,所以结果总是假的,我不知道如何解决这个问题,所以另一个类在Task完成后检查条件。

首先,我的Authorization班级

public class Authorization {
    private static String query = "";
    private static boolean isValid;
    private static Task<Void> task;

    public static void verifyLogin(String username, String password) throws SQLException{
        Status.get().unbind();
        isValid = false;
        task = new Task<Void>() {
            @Override
            protected Void call() throws SQLException {
               while(!isCancelled()) {
                   try {
                       updateMessage("Weryfikacja.");
                       Thread.sleep(200);
                       updateMessage("Weryfikacja..");
                       Thread.sleep(200);
                       updateMessage("Weryfikacja...");
                       Thread.sleep(200);

                       if(username.equals("") || password.equals("")) {
                           task.cancel();
                           updateMessage("Pola nie mogą być puste");
                       } else {
                           query = "SELECT login FROM users WHERE login = ?";
                           Query.execute(query, username);
                           if(!Query.resultSet.next()) {
                               task.cancel();
                               updateMessage("Nie ma takiego użytkownika");
                           } else {
                               query = "SELECT password FROM users WHERE login = ?";
                               Query.execute(query, username);
                               if(Query.resultSet.next()) {
                                   String passwordValue = Query.resultSet.getString(1);
                                   if(!password.equals(passwordValue)) {
                                       task.cancel();
                                       updateMessage("Podane hasło jest błędne");
                                   } else {
                                       task.cancel();
                                       updateMessage("");
                                       isValid = true;
                                   }
                               }
                           }
                       }
                   } catch(InterruptedException e) {
                       if(isCancelled()) {
                           break;
                       }
                   }
               }
               return null;
            }
        };
        Status.get().bind(task.messageProperty());
        new Thread(task).start();
    }

    public static boolean isValid() {
        return isValid;
    }
}

从另一个类调用

  private void login() {
        if( SqlConnection.isConnected()) {
            try{
                Authorization.verifyLogin(String.valueOf(loginInput.getText()), String.valueOf(passwordInput.getText()));
                if(Authorization.isValid()) {
                    //should go to next menu
                    //but never does
                }
            } catch (SQLException e) {
                e.printStackTrace();
                Debug.log(e.toString());
            }
        }
    }

编辑# 很抱歉updateMessage()中有光泽。

1 个答案:

答案 0 :(得分:1)

您的verifyLogin()方法只是在另一个线程中启动验证过程,然后立即退出。在该线程完成之前,isValid标志不会被更改,这会在很晚之后发生。如果您想要执行验证过程然后执行其他操作,那么在verifyLogin()中管理线程并不是真的有意义。

我不太了解你的代码应该做的很多事情;你有一个while(...)循环,据我所知,它只能被执行一次(因此是冗余的)。您似乎也执行两个基本相同的SQL查询。 (第一次检查是否存在具有特定条件的行,如果有,则第二次检索该行。为什么不检索该行并检查它是否存在?)

我会重构这一点,以便validateLogin()方法根本不处理线程,只返回验证结果(例如状态字符串,但也许其他东西是合适的)。

/**
  * @return An empty string if the login is valid, or an error message otherwise
  */

public static String verifyLogin(String username, String password) throws SQLException{
   isValid = false ;
   if(username.equals("") || password.equals("")) {
       return "Pola nie mogą być puste";
   } 
   query = "SELECT login, password FROM users WHERE login = ?";
   Query.execute(query, username);
   if(!Query.resultSet.next()) {
       return "Nie ma takiego użytkownika";
   } 

   String passwordValue = Query.resultSet.getString(2);
   if(!password.equals(passwordValue)) {
       return "Podane hasło jest błędne" ;
   } 


   isValid = true;
   return "" ;

}

现在我将从login()方法管理线程。这样,您可以使用任务的onSucceeded处理程序在任务完成时执行代码:

private void login() {
    if( SqlConnection.isConnected()) {
        Task<String> verifyTask = new Task<String>() {
            @Override
            protected String call() throws SQLException {

                return Authorization.verifyLogin(loginInput.getText(), passwordInput.getText());
            }
        };

        // probably better to use a progress indicator or similar here, but:

        Animation animation = new Timeline(
            new KeyFrame(Duration.ZERO, e -> Status.get().set("Weryfikacja.")),
            new KeyFrame(Duration.millis(200), e -> Status.get().set("Weryfikacja..")),
            new KeyFrame(Duration.millis(400), e -> Status.get().set("Weryfikacja...")),
            new KeyFrame(Duration.millis(600)));
        animation.setCycleCount(Animation.INDEFINITE);


        verifyTask.setOnSucceeded(event -> {
            animation.stop();
            Status.get().set(verifyTask.getValue());
            if(Authorization.isValid()) { // or if (verifyTask.getValue().isEmpty()) 
                // go to next menu
            }
        });

        verifyTask.setOnFailed(event -> {
            animation.stop();
            verifyTask.getException().printStackTrace();
            Debug.log(verifyTask.getException().toString());
        }

        animation.play();
        new Thread(verifyTask()).start();
    }
}