JavaFX e controle de threads

Eu gostaria de travar a Thread atual do meu programa enquanto executo uma segunda thread, pois preciso de seu retorno, para ilustrar meu problema segue o código abaixo:

Task task = new Task() {
            @Override
            protected Object call() {
                try {
                    this.updateMessage("carregando teste...");
                    for (int i = 1; i <= 10; i++) {
                        System.out.println("Número: " + i);
                        Thread.sleep(1000);
                    }
                    this.updateMessage("fim");
                    return "Eba!!!!";
                } catch (InterruptedException ex) {
                    new Logger().erro(this.getClass(), "start(Stage stage)", ex);
                    return null;
                }
            }
        };
        this.abreStageDoJavaFX();
        new Thread(task).start();
        this.fechaStageDoJavaFX();

Quando eu faço o comando new Thread(task).start(); ele inicia a thread mas continua a atual, logo, ele abre e fecha minha tela imediatamente após iniciar a thread. Eu tentei fazer o seguinte:

        abreStageDoJavaFX();
        new Thread(task).start();
        while(!task.isDone()){
            Thread.sleep(1000);
        }
        this.fechaStageDoJavaFX();

E realmente a Thread principal do meu programa ficou presa no while enquanto a segunda thread não terminou, porém, o método this.abrirStageDoJavaFX(); foi executado sem que a tela aparecesse, é como se a view só fosse atualizada após o fim da execução de todo o método que chamou ela, e como esperado o método this.fechaStageDoJavaFX() fechou a tela (que nem chegou a abrir) após sair do while… Alguém sabe como abrir um Stage, iniciar uma thread, esperar até o fim dela, e depois fechar esse stage?

Já tentou usar um Service, ele possui métodos start, succedede failed, em ambos você pode executar ações na UI, há também um método createTask onde vc executa o processamento através de uma Task e esse estará disponível no succeded.

Exemplo:

    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);

    new Service<Integer>() {
        @Override
        public void start() {
            super.start();
            stage.show();
        }

        @Override
        protected Task<Integer> createTask() {
            return new Task<Integer>() {
                @Override
                protected Integer call() throws Exception {
                        Thread.sleep(3000);
                        return 1;
                }
            };
        }

        @Override
        protected void succeeded() {
            // getValue(); Obtem o valor processado na Task
           stage.close();
        }
        
    }.start();
1 curtida

Obrigado por responder @Andrauss, Quanto ao service eu nem sabia que ele existia kkkk, mas enfim, a primeira coisa que estou achando estranho é que você abre a GUI dentro do service, e basicamente quem controla a GUI desse stage no seu exemplo é a segunda thread, e isso não se encaixa bem com o conceito que quero implementar. usando seu exemplo eu gostaria de fazer isso:

Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    //Esse stage é modal
    stage.show();

    Service service = new Service<Integer>() {
        @Override

public void start() {
            super.start();
        }

@Override
        protected Task<Integer> createTask() {
            return new Task<Integer>() {
                @Override
                protected Integer call() throws Exception {
                        Thread.sleep(3000);
                        return 1;
                }
            };
        }

@Override
        protected void succeeded() {
            // getValue(); Obtem o valor processado na Task
           stage.close();
        }
        
    };
service.start();
//Enquanto o service não terminar sua execução nem tente recuperar o retorno
Pessoa retornoDaThread = (Pessoa) service.get();
//Se o service não travar o fluxo atual e esse comando for executado a saída será nula
System.out.println(retornoDaThread.getNome());

Não sei se ficou claro… Mas o controle da GUI ficar dentro da segunda Thread não é um grande problema, pois acredito que mesmo dentro da segunda thread eu ainda consigo um efeito de stage.initModality.APPLICATION_MODAL, meu real problema é dar start na thread, esperar pelo retorno que ela vai gerar, e só depois continuar o fluxo (mas claro, sem interferir na GUI =D), acho que vendo somente as 5 ultimas linhas do exemplo acima você entende, e novamente muito obrigado pelo retorno.

Então basicamente o que quer é que uma tela aguarde a execução em outra tela e receba o retorno da mesma?

Exatamente, o método que quero executar é exatamente esse:

public void setTask(Stage stage, Task task) {
        stage.show();
        lbMensagem.progressProperty().unbind();
        lbMensagem.progressProperty().bind(task.progressProperty());
        new Thread(task).start();
        //aqui deveria esperar o fim da execução
        stage.close();
        retorno = task.get();
    }

Eu recebo o stage e a task prontas de outra classe, não dá pra enfiar a stage dentro da task nesse ponto… então tento inciar a GUI fora da thread, esperar a thread finalizar, e depois fechar, pra tornar o retorno disponível

com base nisso o stage.showAndWait() resolve o problema

@Eduardo_Maranata10 seguindo sua ideia ficaria assim:

public void setTask(Stage stage, Task task) {
        lbMensagem.progressProperty().unbind();
        lbMensagem.progressProperty().bind(task.progressProperty());
        new Thread(task).start();
        stage.showAndWait();
        retorno = task.get();
    }

mas quem daria o stage.close() quando o task terminasse?

Tem como tu colocar a classe completa

De longe sua solução seria colocar no método succeeded

http://stackoverflow.com/questions/13784333/platform-runlater-and-task-in-javafx