Async in JavaFX 1.2 Part 5

今回のテーマは 『複数のタスクをシーケンシャルに実行する』 です。

そろそろ 非同期処理をテーマに書くのも行き詰まってきたのでこの辺で打ち切りかな?

そろそろちゃんとしたアプリケーションも作りたいし...

で 早速本題ですが...
あるタスクが終わった後にその結果をもとにして次のタスクを実行したい時ってありますよね。
通常このような場合 Task#onDone で実装すると思いますが、そうすると Task を部品化しにくくなります。

そこで 今回、複数のタスクを順番に処理する SequentialTask を考えてみました。
次のサンプルは1つ目の Task が自分の名前(スレッド名)を名乗り、それを受けて2つ目の Task が相手の名前を呼んだ後、自分の名前(スレッド名)を名乗ると言う全く意味のないコードです。
しかし、このサンプルには非常に重要なことが隠されています。実は この2つの Task、完全に独立した非同期処理にも関わらず、1つ目の Task が終了した後、その Task の情報をもとに、2つ目の Task が処理されているのです。

Main.fx

import java.lang.*;

var name: String;
SequentialTask {
    task: [
        GreetingTask { myName: bind name with inverse }
        GreetingTask { yourName: bind name }
    ]
}.start();

class GreetingTask extends ActionTask {
    public var myName: String;
    public var yourName: String;
    init {
        action = function() {
            Thread.sleep(2000);
            myName = Thread.currentThread().getName();
        }
        onDone = function() {
            print("Hi, ");
            if (yourName != null) print("{yourName}. ");
            println("My name is {myName}.");
         }
    }
}

※ ActionTask については 『Async in JavaFX 1.2 Part 3』 を参照してください。ただし、action 属性がサブクラスから設定できるように少し修正してあります。

実行結果はこんな感じ...
ちゃんと 2つ目の Task の出力に 1つ目の Task のスレッド名が出力されています。

Hi, My name is task.2.
Hi, task.2. My name is task.3.

SequentialTask.fx

import java.lang.*;
import javafx.async.Task;

public class SequentialTask extends ActionTask {
    
    public-init var task: Task[];
    
    init {
        action = function() {
            for (t in task) {
                t.start();
                while (not t.done) {
                    Thread.sleep(200);
                }
                if (t.failed) break;
            }
        }
    }
    override function stop(): Void {
        for (t in task) {
            t.stop();
        }
    }
}


実際のアプリケーションでは...

  1. ログイン処理をする。
  2. Web にアクセスしてデータを取得し画面の表示を更新する。
  3. データをローカルファイルに保存する。

のように別々のタスクをシーケンシャルに組み合わせて一連の処理を行うといったことが考えられます。

このように、それぞれのタスクを部品化しておけば...
例えば、Refresh ボタンをクリックした時のアクションに 2 と 3 をそのまま使うことができたり、 3 をオプション扱いにした場合、設定が有効な時だけ 3 のタスクをインスタンス化するだけで、簡単に処理を有効にすることができたり、きっと役に立つでしょう。