Platform.runLater e tarefa no JavaFX

Eu tenho feito algumas pesquisas sobre isso, mas ainda estou muito confuso para dizer o mínimo.

Alguém pode me dar um exemplo concreto de quando usar a Task e quando usar Platform.runLater(Runnable); ? Qual é exatamente a diferença? Existe uma regra de ouro para quando usar qualquer um destes?

Também me corrija se eu estiver errado, mas esses dois “Objetos” não são uma maneira de criar outro thread dentro do thread principal em uma GUI (usada para atualizar a GUI)?

Use Platform.runLater(...) para operações rápidas e simples e Task para operações complexas e grandes.

  • Caso de uso para Platform.runLater(...)
  • Caso de uso para Task : Exemplo de Tarefa no Ensemble App

Exemplo: Por que não podemos usar Platform.runLater(...) para cálculos longos (extraídos da referência abaixo).

Problema: encadeamento em segundo plano que apenas conta de 0 a 1 milhão e atualiza a barra de progresso na interface do usuário.

Código usando Platform.runLater(...) :

 final ProgressBar bar = new ProgressBar(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 1000000; i++) { final int counter = i; Platform.runLater(new Runnable() { @Override public void run() { bar.setProgress(counter / 1000000.0); } }); } }).start(); 

Este é um pedaço hediondo de código, um crime contra a natureza (e programação em geral). Primeiro, você perderá células cerebrais apenas olhando para esse duplo ninho de Runnables. Em segundo lugar, vai afundar a fila de events com pequenos Runnables - um milhão deles na verdade. Claramente, precisávamos de alguma API para facilitar a criação de funcionários em segundo plano que, em seguida, se comunicavam com a interface do usuário.

Código usando Tarefa:

 Task task = new Task() { @Override public Void call() { static final int max = 1000000; for (int i = 1; i <= max; i++) { updateProgress(i, max); } return null; } }; ProgressBar bar = new ProgressBar(); bar.progressProperty().bind(task.progressProperty()); new Thread(task).start(); 

não sofre de nenhuma das falhas exibidas no código anterior

Referência: Threading de trabalho no JavaFX 2.0

  • Platform.runLater : Se você precisar atualizar um componente da GUI de um segmento não-GUI, poderá usá-lo para colocar sua atualização em uma fila e ela será manipulada pelo encadeamento da GUI assim que possível.
  • Task implementa a interface Worker que é usada quando você precisa executar uma tarefa longa fora do thread da GUI (para evitar o congelamento do aplicativo), mas ainda precisa interagir com a GUI em algum momento.

Se você estiver familiarizado com o Swing, o primeiro é equivalente ao SwingUtilities.invokeLater e o segundo ao conceito de SwingWorker .

O javadoc da Tarefa fornece muitos exemplos que devem esclarecer como eles podem ser usados. Você também pode consultar o tutorial sobre simultaneidade .

Agora pode ser alterado para a versão lambda

 @Override public void actionPerformed(ActionEvent e) { Platform.runLater(() -> { try { //an event with a button maybe System.out.println("button is clicked"); } catch (IOException | COSVisitorException ex) { Exceptions.printStackTrace(ex); } }); } 

Um motivo para usar um Platform.runLater () explicito pode ser que você vincule uma propriedade na interface do usuário a uma propriedade de serviço (resultado). Então, se você atualizar a propriedade de serviço ligada, você terá que fazer isso via runLater ():

No encadeamento de interface do usuário também conhecido como encadeamento do aplicativo JavaFX:

 ... listView.itemsProperty().bind(myListService.resultProperty()); ... 

na implementação do serviço (trabalhador de segundo plano):

 ... Platform.runLater(() -> result.add("Element " + finalI)); ...