サービスには、サービスの提供されたタスクから返されるオブジェクトの型を指定するために使用されるジェネリック型パラメーターである署名Service<V>
があります。<V>
Foo 型のユーザー定義オブジェクトを返すサービスを定義したい場合、次のように実行できます。
class FooGenerator extends Service<Foo> {
protected Task createTask() {
return new Task<Foo>() {
protected Foo call() throws Exception {
return new Foo();
}
};
}
}
サービスを利用するには:
FooGenerator fooGenerator = new FooGenerator();
fooGenerator.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
@Override public void handle(WorkerStateEvent t) {
Foo myNewFoo = fooGenerator.getValue();
System.out.println(myNewFoo);
}
});
fooGenerator.start();
サービスを開始または再起動する前に毎回入力値をサービスに渡したい場合は、もう少し注意する必要があります。サービスに入力したい値を、サービス上の設定可能なメンバーとして追加できます。これらのセッターは、サービスの start メソッドが呼び出される前に、JavaFX アプリケーションスレッドから呼び出すことができます。次に、サービスのタスクが作成されたら、パラメーターをサービスのタスクのコンストラクターに渡します。
これを行うときは、すべての情報をスレッド間で不変に受け渡しできるようにするのが最善です。以下の例では、Foo オブジェクトが入力パラメーターとしてサービスに渡され、受信した入力に基づいて Foo オブジェクトがサービスの出力として渡されます。しかし、Foo 自体の状態はそのコンストラクターでのみ初期化されます。Foo のインスタンスは不変であり、作成後に変更することはできず、そのすべてのメンバー変数は最終的なものであり、変更することはできません。これにより、別のスレッドが同時に状態を上書きするのではないかと心配する必要がないため、プログラムについての推論がはるかに簡単になります。少し複雑に思えますが、すべてが非常に安全になります。
class FooModifier extends Service<Foo> {
private Foo foo;
void setFoo(Foo foo) { this.foo = foo; }
@Override protected Task createTask() {
return new FooModifierTask(foo);
}
private class FooModifierTask extends Task<Foo> {
final private Foo fooInput;
FooModifierTask(Foo fooInput) { this.fooInput = fooInput; }
@Override protected Foo call() throws Exception {
Thread.currentThread().sleep(1000);
return new Foo(fooInput);
}
}
}
class Foo {
private final int answer;
Foo() { answer = random.nextInt(100); }
Foo(Foo input) { answer = input.getAnswer() + 42; }
public int getAnswer() { return answer; }
}
Service
サービスjavadocに入力を提供する別の例があります。
サービスからカスタム ユーザー例外を返すには、サービスのタスク呼び出しハンドラー中にユーザー例外をスローするだけです。例えば:
class BadFooGenerator extends Service<Foo> {
@Override protected Task createTask() {
return new Task<Foo>() {
@Override protected Foo call() throws Exception {
Thread.currentThread().sleep(1000);
throw new BadFooException();
}
};
}
}
そして、例外は次のように取得できます。
BadFooGenerator badFooGenerator = new BadFooGenerator();
badFooGenerator.setOnFailed(new EventHandler<WorkerStateEvent>() {
@Override public void handle(WorkerStateEvent t) {
Throwable ouch = badFooGenerator.getException();
System.out.println(ouch.getClass().getName() + " -> " + ouch.getMessage());
}
});
badFooGenerator.start();
これを試すために使用できる実行可能なサンプルをいくつか作成しました。