103 votes

Platform.runLater et Task en JavaFX

J'ai fait quelques recherches à ce sujet, mais je suis encore TRÈS confuse, c'est le moins que l'on puisse dire.

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 ? Y a-t-il une règle d'or pour savoir quand utiliser l'un de ces produits ?

Corrigez-moi si je me trompe, mais ces deux "objets" ne sont-ils pas un moyen de créer un autre thread à l'intérieur du thread principal dans une interface graphique (utilisé pour mettre à jour l'interface graphique) ?

126voto

invariant Points 2928

Utilisez Platform.runLater(...) pour des opérations simples et rapides et Task pour les opérations complexes et importantes .

Exemple : Pourquoi ne pouvons-nous pas utiliser Platform.runLater(...) pour de longs calculs (Tiré de la référence ci-dessous).

Problème : Fil d'arrière-plan qui compte de 0 à 1 million et met à jour la barre de progression dans l'interface utilisateur.

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 hideux morceau de code, un crime contre la nature (et le la programmation en général). Tout d'abord, vous allez perdre des cellules cérébrales juste en regardant cette double imbrication de Runnables. Deuxièmement, cela va submerger la queue d'événements avec des petits Runnables - un million d'entre eux en fait. Il est clair que nous avions besoin d'une API pour faciliter l'écriture de l'arrière-plan qui communiquent ensuite avec l'interface utilisateur.

Code utilisant 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 du travailleur dans JavaFX 2.0

70voto

assylias Points 102015
  • Platform.runLater : Si vous devez mettre à jour un composant GUI à partir d'un thread non-GUI, vous pouvez utiliser cela pour mettre votre mise à jour dans une file d'attente et elle sera traitée par le thread GUI dès que possible.
  • Task met en œuvre le Worker qui est utilisée lorsque vous devez exécuter une tâche longue en dehors du thread de l'interface graphique (pour éviter de geler votre application) mais que vous devez quand même interagir avec l'interface graphique à un moment donné.

Si vous êtes familier avec Swing, le premier est équivalent à SwingUtilities.invokeLater et le second au concept de SwingWorker .

En javadoc de Task donne de nombreux exemples qui devraient clarifier la manière dont ils peuvent être utilisés. Vous pouvez également vous référer à le tutoriel sur la concurrence .

14voto

Caglar Sekmen Points 144

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);
        }
    });
}

3voto

Une raison d'utiliser une Platform.runLater() explicite pourrait être que vous avez lié une propriété dans l'interface utilisateur à une propriété de service (résultat). Ainsi, si vous mettez à jour la propriété de service liée, vous devez le faire via runLater() :

Dans le thread de l'interface utilisateur, également connu sous le nom de thread de l'application JavaFX :

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

dans la mise en œuvre du service (travailleur en arrière-plan) :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X