web-dev-qa-db-ja.com

Platform.runLaterとJavaFXのタスク

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

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

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

75
Marc Rasmussen

すばやく簡単な操作には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();

これは恐ろしいコードの塊であり、自然(およびプログラミング全般)に対する犯罪です。まず、このRunnableの二重のネストを見るだけで、脳細胞が失われます。第二に、イベントキューを小さなRunnableで埋め尽くします-実際には100万個です。明らかに、バックグラウンドワーカーを簡単に記述して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();

前のコードで示された欠陥はありません

リファレンス:JavaFX 2.0のワーカースレッディング

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

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

Taskのjavadoc は、使用方法を明確にする多くの例を示しています。 並行性に関するチュートリアル を参照することもできます。

53
assylias

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

@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);
        }
    });
}
9
Caglar Sekmen

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

JavaFXアプリケーションスレッドとも呼ばれるUIスレッドでは:

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

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

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