Platform.runLaterとJavaFXのタスク


88

私はこれについていくつかの研究を行ってきましたが、控えめに言ってもまだ非常に混乱しています。

Taskいつ使用するPlatform.runLater(Runnable);か、いつ使用するかについて具体的な例を教えてもらえますか?違いは正確には何ですか?これらのいずれかをいつ使用するかについての黄金律はありますか?

また、私が間違っている場合は訂正してください。ただし、これら2つの「オブジェクト」は、GUIのメインスレッド内に別のスレッドを作成する方法ではありませんか(GUIの更新に使用されます)。

回答:


108

Platform.runLater(...)迅速で単純な操作、およびTask複雑で大規模な操作に使用します。

例:Platform.runLater(...)長い計算に使用できない理由(以下の参照から取得)。

問題:0から100万までカウントし、UIのプログレスバーを更新するバックグラウンドスレッド。

使用するコード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();

これは恐ろしいコードの塊であり、自然(およびプログラミング一般)に対する犯罪です。まず、Runnablesのこの二重の入れ子を見ているだけで脳細胞が失われます。第二に、それは小さなRunnablesでイベントキューを圧倒するでしょう-実際にはそれらの百万。明らかに、UIと通信するバックグラウンドワーカーを簡単に作成できるようにするためのAPIが必要でした。

タスクを使用したコード:

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

それは前のコードで示された欠陥のどれにも苦しんでいません

参照: JavaFX2.0でのワーカースレッド


Ensembleアプリリンクのタスク例は機能しなくなります。
cugomastik 2014

これは正しいリンクですが、編集が2文字しかないため、編集できません。
Aerus 2015年

29
1つは「迅速な」操作用で、もう1つは「複雑な」操作用であると言うのは、少し誤解を招く恐れがあります。結局のところ、主な違いは、1つは別の場所からJFX GUIスレッドでコードを実行できることと、もう1つは正反対のことです-GUIスレッドからバックグラウンドスレッドでコードを実行できることです(プロセスでGUIスレッドと通信できます)。
セルゲイタチェノフ2015年

各シーンの画像を保存したいのですが、時間がかかります。タスクを介して別のスレッドで実行すると問題が発生しますか?私は、すべてのGUI関連の作業がFxApplicationスレッドで行われる必要があることを理解しました。
StephenBoesch 2015

@ Sergey-Tachenovでは、progressのように単一のプロパティを更新するだけでは不十分な場合に、タスクスレッドからrunLater()を使用してGUIスレッドを更新しますか?
simpleuser 2016年

58
  • Platform.runLater:GUI以外のスレッドからGUIコンポーネントを更新する必要がある場合は、それを使用して更新をキューに入れることができ、GUIスレッドによってできるだけ早く処理されます。
  • TaskWorker(アプリケーションのフリーズを回避するために)GUIスレッドの外部で長いタスクを実行する必要があるが、ある段階でGUIと対話する必要がある場合に使用されるインターフェースを実装します。

Swingに精通している場合、前者はSwingUtilities.invokeLaterの概念と同等であり、後者はの概念と同等ですSwingWorker

Taskjavadocには、それらの使用方法を明確にする必要のある多くの例があります。並行性に関するチュートリアルも参照できます。


ありがとうプラットフォームの使い方の簡単な例を挙げていただけますか?GUIスレッドの外で使用できますか?そして、ドキュメントのタスクの例は本当に不明確です
Marc Rasmussen

はいPlatform.runLaterはGUIスレッドの外部で使用できます-それが主な目的です。このチュートリアルは、javadocよりも有益なタスクに役立つ場合があります。
assylias

3
:あなたはこのようPlatform.runLaterを使用するPlatform.runLater(new Runnable() {public void run() {updateYourGuiHere();}});
assylias

GUIコンポーネントをどのように使用できるか=:S
Marc Rasmussen

1
@KevinMeredithタスクのcallメソッドはFXスレッドで呼び出されるべきではありませんが、タスクはFXスレッドで実行されるブリッジメソッド(updateProgressなど)を提供します。詳細については、javadocとチュートリアルを参照してください。
assylias 2016

12

ラムダバージョンに変更できるようになりました

@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
GUIイベントを処理している場合は、GUIスレッドを使用しています。では、なぜrunLater()を使用するのでしょうか。
TFuto 2015年

あなたが正しい間、Caglarの答えはラムダ式の使用を強調しようとしていましたが、必ずしも良いコーディング例を与えるためではありませんでした。私が使用するPlatform.runLater(() -> progressBar.setProgress(X/Y));
Taelsin 2016年

2

明示的なPlatform.runLater()を使用する理由の1つは、UIのプロパティをサービス(結果)プロパティにバインドしたことである可能性があります。したがって、バインドされたサービスプロパティを更新する場合は、runLater()を介してこれを行う必要があります。

JavaFXアプリケーションスレッドとも呼ばれるUIスレッドでは、次のようになります。

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

サービス実装(バックグラウンドワーカー):

...
Platform.runLater(() -> result.add("Element " + finalI));
...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.