J'ai fait des recherches à ce sujet mais je suis encore TRÈS confus pour le moins.
Quelqu'un peut-il me donner un exemple concret de quand utiliser Task
et quand utiliser Platform.runLater(Runnable);
? Quelle est exactement la différence? Existe-t-il une règle d'or pour utiliser l'un ou l'autre?
Corrigez-moi également si je me trompe, mais ces deux "objets" ne sont-ils pas un moyen de créer un autre thread dans le thread principal d'une interface graphique (utilisé pour la mise à jour de l'interface graphique)?
Utilisez Platform.runLater(...)
pour des opérations simples et rapides et Task
pour des opérations complexes et volumineuses.
Platform.runLater(...)
Task
: exemple de tâche dans l'ensemble AppExemple: Pourquoi ne pouvons-nous pas utiliser Platform.runLater(...)
pour des calculs longs (Tiré de la référence ci-dessous).
Problème: le fil d’arrière-plan ne compte que de 0 à 1 million et met à jour la barre de progression dans l’UI.
Code utilisant 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();
C'est un morceau de code hideux, un crime contre nature (et la programmation en général). Tout d’abord, vous allez perdre les cellules cérébrales en regardant simplement cette double imbrication de Runnables. Deuxièmement, il va submerger la file d’événements avec de petits Runnables - un million d’entre eux en fait. De toute évidence, nous avions besoin d’API pour faciliter l’écriture de travailleurs d’arrière-plan qui communiquent avec l’UI.
Code à l'aide de Task:
Task task = new Task<Void>() {
@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();
il ne souffre d'aucun des défauts exposés dans le code précédent
Référence: Threading des travailleurs dans JavaFX 2.
Platform.runLater
: Si vous devez mettre à jour un composant d'interface graphique à partir d'un thread non graphique, vous pouvez l'utiliser pour placer votre mise à jour dans une file d'attente. Elle sera traitée par le thread d'interface graphique dès que possible.Task
implémente l'interface Worker
qui est utilisée lorsque vous devez exécuter une tâche longue en dehors du thread d'interface graphique (pour éviter de geler votre application), mais que vous devez néanmoins interagir avec l'interface graphique à un moment donné.Si vous connaissez Swing, le premier est équivalent à SwingUtilities.invokeLater
et le dernier au concept de SwingWorker
.
Le javadoc de Task donne de nombreux exemples qui devraient préciser comment ils peuvent être utilisés. Vous pouvez également vous référer à le didacticiel sur la simultanéité .
Il peut maintenant être changé en version 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);
}
});
}
Une raison d'utiliser explicitement Platform.runLater () pourrait être que vous avez lié une propriété de l'interface utilisateur à une propriété de service (résultat). Donc, si vous mettez à jour la propriété du service lié, vous devez le faire via runLater ():
Dans le thread d'interface utilisateur également appelé thread d'application JavaFX:
...
listView.itemsProperty().bind(myListService.resultProperty());
...
mise en œuvre en service (agent d'arrière-plan):
...
Platform.runLater(() -> result.add("Element " + finalI));
...