Способы реализации функции (callback) функции обратного вызова в Java

👁 380 просмотров
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 1,00 из 5)
Загрузка...

Callback — функция обратного вызова. Используется тогда, когда необходимо выполнить определенный кусок кода, передав данный кусок кода в виде параметра методу и, естественно, данный кусок будет исполняться внутри переданного метода. Чтобы передать данный кусок кода, нам необходимо это кусок кода как-то именовать, естественно, что в Java мы будет это организовать в виде метода и будем передавать этот метод в виде аргумента другим методам.

Когда и где это может быть использовано?

Для начала, рассмотрим задачу вывода диалогового окна, средствами JavaFX. Так как JavaFX не содержит в арсенале понятие диалоговое окно, то нам придется его создавать самим. Такое окно может выводить любую информацию в виде элемента управления или просто текста. Нам необходимо как-то обработать события, которые расположены на данном диалоговом окне. Для решения данной задачи, сначала, воспользуемся решением без использования callback

public class Dialog {
    /** Интерфейс для обработки события*/
    public static String result = null;//Создадим поле хранения текущего значения
      
    public static void setResult(String result)//Реализуем setter
    {
        Dialog.result = result;
    }
    public static String getResult()//Реализуем getter
    {
        return Dialog.result;
    }

    //Метод реализации вывода диалогового окна
    public static void showAlert(String title){

          //Создаем новый экземпляр стадии(будет выполняться наряду с основным потоком программы)
          final Stage dlgStage = new Stage();

          //Создадим кнопку
          Button btnOk = new Button("Ok");
          
          //Прикрепим к кнопке событие
          btnOk.setOnAction(new EventHandler(){
              @Override
              public void handle(ActionEvent arg0) {
                  setResult("Yo click Ok!");//Устанавливаем значение при нажатии на кнопку
                  dlgStage.close();//Закрываем диалоговое окно при нажатии
              }
          });

          //Текстовое поле для вывода информации
          Label lblTitle = new Label(title);
          lblTitle.setFont(Font.font("Amble CN", FontWeight.NORMAL, 14));

          //Создаем контейнер для вертикального выравнивания элементов
          VBox vbox = new VBox(lblTitle,btnOk);
          vbox.setAlignment(Pos.CENTER);
          vbox.setMinSize(300, 200);

          //Создаем новую сцену и передаем ей контейнер
          Scene dlgScene = new Scene(vbox);

          //Устанавливаем сцену, инициализировав стили и т.д.
          dlgStage.setScene(dlgScene);
          dlgStage.initStyle(StageStyle.UNDECORATED);
          dlgStage.initModality(Modality.APPLICATION_MODAL);
          dlgStage.setMinWidth(300);
          dlgStage.setMinHeight(200);
          dlgStage.show();      
  }
}

Наш класс реализации диалогового окна готов, настал момент вывести его на экран, написав следующий код

Dialog.showAlert("Hello world!");
if(Dialog.getResult() != null)
{
  System.out.println(Dialog.getResult());// Результат, записанный при нажатии
}

В результате мы получим следующий результат на экране

java-dialog-callback

Нажмем на кнопку и посмотрим на вывод в консоле NetBeans, где у нас ничего не выведется в первый раз, потому что диалоговое окно выполняется своим потоком, а программа своим и после нажатия на «ok» мы инициализируем значение поля result, закрываем диалоговое окно, но повторно — то этот код не выпонится, поэтому значение в result при первом запуске будет null, как мы его инициализировали в классе Dialog. При повторном выполнении данного кода у нас выведется тоже самое окно, но значение уже будет не текущее, а предыдущего нажатия, что не есть нормально, так как создается 2 потока: 1- поток программы, 2 — поток диалогового окна.

 Решение проблемы с помощью callback

Код ниже именуется как callback.

new EventHandler<ActionEvent>(){
    @Override 
    public void handle(ActionEvent arg0){    
    dlgStage.close();
  }
}

Callback не возвращает type, как вы можете видеть выше в примере, он void.

Callback — и имеют методы, которые вы получаете как аргументы в другом методе.  Другой метод должен вызвать callback метод, когда он пожелает. Это значит, что callback — и имеют асинхронность.

В вашем примере, он вызывает callback, когда вы жмете на кнопку.

И в заключении, вы не сможете возвратить его, используя return.

Что делать ?

Вы можете вызвать метод из вашего callback и отправить ваше возвращаемое значение ему как аргумент.

Пример:

btnCancel.setOnAction( newEventHandler<ActionEvent>(){
    @Override
    public void handle(ActionEvent arg0){

        YourClass.setReturnValue("This is button Cancel");
        dlgStage.close();
   }
 });

Где setReturnValue  -метод принадлежащий вашему классу YourClass или его экземпляр, который будет содержать ваше возвращаемое значение.

Другой и лучшим путем подхода будет создание класса, который будет наследовать Stage. Также в вашем  showPrompt методе вы должны блокировать выполнение основного потока, используя showAndWait() или похожим образом.

В заключении, вы не можете создавать весь Prompt из только одного метода.