Platform.runLater e Task in JavaFX


90

Ho fatto alcune ricerche su questo, ma sono ancora MOLTO confuso per non dire altro.

Qualcuno può darmi un esempio concreto di quando usare Taske quando usare Platform.runLater(Runnable);? Qual è esattamente la differenza? Esiste una regola d'oro per quando utilizzare uno di questi?

Correggimi anche se sbaglio ma questi due "Oggetti" non sono un modo per creare un altro thread all'interno del thread principale in una GUI (usato per aggiornare la GUI)?

Risposte:


110

Utilizzare Platform.runLater(...)per operazioni rapide e semplici e Taskper operazioni complesse e di grandi dimensioni.

Esempio: perché non possiamo usarlo Platform.runLater(...)per calcoli lunghi (preso dal riferimento sotto).

Problema: thread in background che conta da 0 a 1 milione e aggiorna la barra di avanzamento nell'interfaccia utente.

Codice utilizzando 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();

Questo è un orribile pezzo di codice, un crimine contro la natura (e la programmazione in generale). Innanzitutto, perderai cellule cerebrali solo guardando questo doppio annidamento di Runnables. In secondo luogo, riempirà la coda degli eventi con piccoli Runnable - un milione in effetti. Chiaramente, avevamo bisogno di alcune API per semplificare la scrittura di worker in background che poi comunicano di nuovo con l'interfaccia utente.

Codice utilizzando attività:

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

non soffre di nessuno dei difetti mostrati nel codice precedente

Riferimento: thread di lavoro in JavaFX 2.0


L'esempio di attività nel collegamento dell'app Ensemble non funzionerà più.
Cugomastik

Questo è il collegamento corretto ma non posso modificarlo perché la modifica è di soli 2 caratteri.
Aerus

29
Dire che uno per le operazioni "veloci" e un altro per quelle "complesse" è un po 'fuorviante. La differenza principale, dopotutto, è che uno consente di eseguire codice nel thread della GUI JFX da qualche altra parte, e l'altro fa l'esatto opposto: consente di eseguire codice nel thread in background dal thread della GUI (aggiungendo un bonus di essere in grado di comunicare con il thread della GUI nel processo).
Sergei Tachenov

Voglio salvare un'immagine di ciascuna delle scene e questo richiederà tempo. Ciò causerà problemi se eseguito su un thread separato tramite Task? Ho capito che tutto il lavoro relativo alla gui deve essere eseguito sul thread FxApplication.
StephenBoesch

@ Sergey-Tachenov Quindi usi runLater () da un thread di attività per aggiornare il thread della GUI nei casi in cui desideri fare di più che aggiornare una singola proprietà come progress?
simpleuser

59
  • Platform.runLater: Se è necessario aggiornare un componente della GUI da un thread non GUI, è possibile utilizzarlo per mettere in coda l'aggiornamento e verrà gestito dal thread della GUI il prima possibile.
  • Taskimplementa l' Workerinterfaccia che viene utilizzata quando è necessario eseguire un'attività lunga al di fuori del thread della GUI (per evitare il congelamento dell'applicazione) ma è comunque necessario interagire con la GUI in qualche fase.

Se hai familiarità con lo Swing, il primo equivale al SwingUtilities.invokeLaterconcetto di SwingWorker.

Il javadoc di Task fornisce molti esempi che dovrebbero chiarire come possono essere utilizzati. Puoi anche fare riferimento al tutorial sulla concorrenza .


Grazie Puoi fare un piccolo esempio di come utilizzare la piattaforma? Puoi usarlo al di fuori del thread della GUI o? E gli esempi di attività nei documenti sono davvero poco chiari
Marc Rasmussen

Sì Platform.runLater può essere utilizzato al di fuori del thread della GUI: questo è il suo scopo principale. Potresti trovare questo tutorial sulle attività più informativo di javadoc.
assylias

3
Utilizzi Platform.runLater in questo modo:Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
assylias

come potrò utilizzare i componenti della GUI quindi =: S
Marc Rasmussen

1
@KevinMeredith Il metodo di chiamata di Task non dovrebbe essere chiamato sul thread FX, ma Task fornisce metodi bridge (updateProgress ecc.) Che vengono eseguiti sul thread FX. Vedi javadoc e tutorial per maggiori informazioni.
assylias

12

Ora può essere modificato in versione 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);
        }
    });
}

8
Se stai gestendo un evento della GUI, sei nel thread della GUI. Perché dovresti usare runLater () allora?
TFuto

Anche se hai ragione, la risposta di Caglar stava cercando di evidenziare l'uso di un'espressione lambda, non necessariamente per fornire un buon esempio di codifica. Io usoPlatform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin

2

Un motivo per utilizzare un Platform.runLater () esplicito potrebbe essere che hai associato una proprietà nell'interfaccia utente a una proprietà del servizio (risultato). Quindi, se aggiorni la proprietà del servizio associato, devi farlo tramite runLater ():

Nel thread dell'interfaccia utente noto anche come thread dell'applicazione JavaFX:

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

nell'implementazione del servizio (operatore in background):

...
Platform.runLater(() -> result.add("Element " + finalI));
...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.