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