Platform.runLater dan Tugas di JavaFX

90

Saya telah melakukan beberapa penelitian tentang hal ini tetapi saya masih SANGAT bingung untuk sedikitnya.

Adakah yang bisa memberi saya contoh konkret tentang kapan harus menggunakan Taskdan kapan harus menggunakan Platform.runLater(Runnable);? Apa sebenarnya bedanya? Apakah ada aturan emas tentang kapan harus menggunakan semua ini?

Juga koreksi saya jika saya salah, tetapi bukankah kedua "Objek" ini merupakan cara untuk membuat utas lain di dalam utas utama dalam GUI (digunakan untuk memperbarui GUI)?

Marc Rasmussen
sumber

Jawaban:

110

Gunakan Platform.runLater(...)untuk operasi cepat dan sederhana dan Taskuntuk operasi kompleks dan besar.

Contoh: Mengapa tidak bisa kita gunakan Platform.runLater(...)untuk perhitungan panjang (Diambil dari referensi di bawah).

Masalah: Utas latar belakang yang hanya menghitung dari 0 hingga 1 juta dan memperbarui bilah kemajuan di UI.

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

Ini adalah sebongkah kode yang mengerikan, kejahatan terhadap alam (dan pemrograman secara umum). Pertama, Anda akan kehilangan sel-sel otak hanya dengan melihat sarang ganda Runnable ini. Kedua, itu akan membanjiri antrian acara dengan Runnable kecil - sejuta di antaranya sebenarnya. Jelas, kami membutuhkan beberapa API untuk mempermudah menulis pekerja latar belakang yang kemudian berkomunikasi kembali dengan UI.

Kode menggunakan Tugas:

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

itu tidak memiliki kekurangan yang ditunjukkan pada kode sebelumnya

Referensi: Worker Threading di JavaFX 2.0

invarian
sumber
Contoh Tugas di tautan Aplikasi Ensemble tidak akan berfungsi lagi.
Cugomastik
Ini adalah tautan yang benar tetapi saya tidak dapat mengeditnya karena pengeditan hanya 2 karakter.
Aerus
29
Mengatakan satu untuk operasi "cepat" dan satu lagi untuk operasi "kompleks" agak menyesatkan. Perbedaan utama, bagaimanapun, adalah bahwa yang satu memungkinkan untuk menjalankan kode di utas GUI JFX dari tempat lain, dan yang lain melakukan sebaliknya - memungkinkan untuk menjalankan kode di utas latar belakang dari utas GUI (menambahkan bonus dapat berkomunikasi dengan utas GUI dalam proses).
Sergei Tachenov
Saya ingin menyimpan Gambar dari setiap adegan - dan ini akan memakan waktu. Apakah itu akan menyebabkan masalah saat dijalankan di utas terpisah melalui Tugas? Saya memahami bahwa semua pekerjaan terkait gui perlu dilakukan di utas FxApplication.
StephenBoesch
@ Sergey-Tachenov Jadi, Anda menggunakan runLater () dari utas Tugas untuk memperbarui utas GUI jika Anda ingin melakukan lebih dari sekadar memperbarui satu properti seperti kemajuan?
simpleuser
59
  • Platform.runLater: Jika Anda perlu memutakhirkan komponen GUI dari utas non-GUI, Anda dapat menggunakannya untuk meletakkan pemutakhiran dalam antrian dan itu akan ditangani oleh utas GUI secepat mungkin.
  • Taskmengimplementasikan Workerantarmuka yang digunakan saat Anda perlu menjalankan tugas yang lama di luar utas GUI (untuk menghindari pembekuan aplikasi Anda) tetapi masih perlu berinteraksi dengan GUI pada tahap tertentu.

Jika Anda terbiasa dengan Swing, yang pertama sama dengan SwingUtilities.invokeLaterkonsep Swing dan yang terakhir SwingWorker.

The javadoc dari Task memberikan banyak contoh yang harus menjelaskan bagaimana mereka dapat digunakan. Anda juga bisa merujuk ke tutorial tentang konkurensi .

assylias
sumber
Terima kasih. Bisakah Anda memberikan contoh kecil bagaimana menggunakan platform? Bisakah Anda menggunakannya di luar utas gui atau? Dan contoh tugas di dokumen benar-benar tidak jelas
Marc Rasmussen
Ya Platform.runLater dapat digunakan di luar utas GUI - itulah tujuan utamanya. Anda mungkin menemukan tutorial tentang tugas ini lebih informatif daripada javadoc.
assylias
3
Anda menggunakan Platform.runLater seperti ini:Platform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
assylias
bagaimana saya bisa menggunakan komponen GUI kemudian =: S
Marc Rasmussen
1
@KevinMeredith Metode panggilan Tugas tidak boleh dipanggil di thread FX - tetapi Tugas menyediakan metode penghubung (updateProgress dll.) Yang berjalan di thread FX. Lihat javadoc & tutorial untuk info lebih lanjut.
assylias
12

Sekarang dapat diubah ke versi 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);
        }
    });
}
Cugomastik
sumber
8
Jika Anda menangani acara GUI, Anda berada di utas GUI. Lalu mengapa Anda menggunakan runLater ()?
TFuto
Meskipun Anda benar, jawaban Caglar mencoba menyoroti penggunaan ekspresi lambda, tidak serta merta memberikan contoh pengkodean yang baik. Saya menggunakanPlatform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin
2

Salah satu alasan untuk menggunakan explicite Platform.runLater () mungkin karena Anda mengikat properti di ui ke properti layanan (hasil). Jadi jika Anda memperbarui properti layanan terikat, Anda harus melakukan ini melalui runLater ():

Dalam thread UI juga dikenal sebagai thread Aplikasi JavaFX:

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

dalam implementasi Layanan (pekerja latar belakang):

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