JavaFX'te Platform.runLater ve Task


90

Bu konuda biraz araştırma yapıyorum ama en azından söylemek gerekirse hala ÇOK kafam karışık.

Biri bana ne zaman Taskve ne zaman kullanılacağına dair somut bir örnek verebilir Platform.runLater(Runnable);mi? Aradaki fark tam olarak nedir? Bunlardan herhangi birinin ne zaman kullanılacağına dair altın bir kural var mı?

Ayrıca yanılıyorsam da düzeltin, ancak bu iki "Nesne" bir GUI'deki ana iş parçacığı içinde başka bir iş parçacığı oluşturmanın bir yolu değil mi (GUI'yi güncellemek için kullanılır)?

Yanıtlar:


110

Kullanın Platform.runLater(...)hızlı ve basit işlemler için ve Taskkarmaşık ve büyük operasyonlar için.

Örnek: Neden Platform.runLater(...)uzun hesaplamalar için kullanamıyoruz (Aşağıdaki referanstan alınmıştır).

Sorun: 0'dan 1 milyona kadar sayılan ve UI'deki ilerleme çubuğunu güncelleyen arka plan iş parçacığı.

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

Bu, korkunç bir kod parçası, doğaya karşı bir suç (ve genel olarak programlama). İlk olarak, sadece Runnables'ın bu çift yuvasına bakarak beyin hücrelerini kaybedeceksiniz. İkincisi, olay kuyruğunu küçük Runnable'larla batıracak - aslında bir milyon. Açıkçası, arka planda çalışanların yazılmasını kolaylaştırmak için bazı API'lere ihtiyacımız vardı ve ardından kullanıcı arayüzü ile geri iletişim kurduk.

Görevi Kullanan Kod:

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

önceki kodda sergilenen kusurların hiçbirinden muzdarip değil

Referans: JavaFX 2.0'da Çalışan İş Parçacığı Oluşturma


Ensemble App bağlantısındaki Görev Örneği artık çalışmayacak.
Cugomastik

Bu doğru bağlantı, ancak düzenleme yalnızca 2 karakter olduğu için onu içinde düzenleyemiyorum.
Aerus

29
Birinin "hızlı" operasyonlar ve diğerinin "karmaşık" işlemler için olduğunu söylemek biraz yanıltıcıdır. Sonuçta temel fark, birinin JFX GUI iş parçacığında başka bir yerden kod çalıştırılmasına izin vermesi ve diğerinin tam tersini yapmasıdır - GUI iş parçacığından arka planda kod çalıştırmaya izin verir ( işlemdeki GUI iş parçacığı ile iletişim kurabilir).
Sergei Tachenov

Her sahnenin bir Görüntüsünü kaydetmek istiyorum - bu zaman alacaktır. Bu, Görev aracılığıyla ayrı bir iş parçacığında çalıştırıldığında sorunlara neden olur mu? GUI ile ilgili tüm çalışmaların FxApplication iş parçacığında yapılması gerektiğini anladım.
StephenBoesch

@ Sergey-Tachenov Yani ilerleme gibi tek bir özelliği güncellemekten daha fazlasını yapmak istediğiniz durumlarda GUI iş parçacığını güncellemek için bir Görev dizisindeki runLater () işlevini kullanıyorsunuz?
simpleuser

59
  • Platform.runLater: GUI olmayan bir iş parçacığından bir GUI bileşenini güncellemeniz gerekiyorsa, güncellemenizi bir sıraya koymak için bunu kullanabilirsiniz ve mümkün olan en kısa sürede GUI iş parçacığı tarafından işlenecektir.
  • TaskWorkerGUI iş parçacığı dışında uzun bir görev çalıştırmanız gerektiğinde (uygulamanızı dondurmaktan kaçınmak için), ancak yine de bir aşamada GUI ile etkileşime girmeniz gerektiğinde kullanılan arabirimi uygular .

Swing'e aşina iseniz, ilki ile eşdeğerdir SwingUtilities.invokeLaterve ikincisi kavramına eşdeğerdir SwingWorker.

Görev Javadoc onlar nasıl kullanılabileceğini açıklamak gerekir pek çok örnek vermektedir. Eşzamanlılık ile ilgili eğiticiye de başvurabilirsiniz .


Teşekkürler Platformun nasıl kullanılacağına dair küçük bir örnek verebilir misiniz? Bunu gui iş parçacığının dışında kullanabilir misin? Dokümanlardaki görev örnekleri gerçekten belirsiz
Marc Rasmussen

Evet Platform.runLater, GUI iş parçacığı dışında kullanılabilir - ana amacı budur. Bu öğreticiyi görevler hakkında javadoc'tan daha bilgilendirici bulabilirsiniz .
assylias

3
Platform.run kullanıyorsunuz Daha sonra şu şekilde:Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
assylias

GUI bileşenlerini nasıl kullanabileceğim o zaman =: S
Marc Rasmussen

1
@KevinMeredith Task'ın çağrı yöntemi FX iş parçacığında çağrılmamalıdır - ancak Task, FX iş parçacığında çalışan köprü yöntemleri (updateProgress vb.) Sağlar. Daha fazla bilgi için javadoc ve öğreticilere bakın.
assylias

12

Artık lambda versiyonuna değiştirilebilir

@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
Bir GUI olayını işliyorsanız, GUI iş parçacığındasınız. O halde neden runLater () kullanmalısınız?
TFuto

Haklıyken Caglar'ın cevabı, iyi bir kodlama örneği vermesi gerekmeden, lambda ifadesinin kullanımını vurgulamaya çalışıyordu. Ben kullanıyorumPlatform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin

2

Explicite Platform.runLater () kullanmanın bir nedeni, kullanıcı arabirimindeki bir özelliği bir hizmet (sonuç) özelliğine bağlamanız olabilir. Dolayısıyla, bağlı hizmet özelliğini güncellerseniz, bunu runLater () aracılığıyla yapmanız gerekir:

UI iş parçacığında JavaFX Uygulama iş parçacığı olarak da bilinir:

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

Hizmet uygulamasında (arka plan çalışanı):

...
Platform.runLater(() -> result.add("Element " + finalI));
...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.