4

JavaFX2のサービスとUIの間でユーザー定義オブジェクトとユーザー定義(チェック)例外を通信する方法は? 例では、プロパティとしてサービスに送信される文字列と、UI に返される監視可能な文字列の配列のみを示しています。

プロパティは単純な型に対してのみ定義されているようです。StringProperty、IntegerProperty、DoubleProperty など。現在、Task で操作し、生成された出力データで更新するユーザー定義オブジェクト (単純な型ではない) があります。Taskのコンストラクターを介して渡すServiceのコンストラクターを介して送信しています。プロパティを介してパラメーターを渡す必要があるという制限について疑問に思いました。また、タスクの操作中に例外がスローされた場合、サービスから UI にどのように渡されますか? getException() メソッドのみが表示され、従来のスロー/キャッチは表示されません。

プロパティhttp://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm

サービスとタスクhttp://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

サービス javadoc http://docs.oracle.com/javafx/2/api/javafx/concurrent/Service.html#getException ()

「Task は JavaFX GUI アプリケーションで使用するように設計されているため、パブリック プロパティへのすべての変更、状態、エラー、およびイベント ハンドラの変更通知がすべてメインの JavaFX アプリケーション スレッドで発生することが保証されます。これらのプロパティへのアクセスバックグラウンド スレッド (call() メソッドを含む) から実行すると、実行時例外が発生します。

タスクが動作する不変の状態ですべてのタスクを初期化することを強くお勧めします。これは、Task の実行に必要なパラメーターを受け取る Task コンストラクターを提供することによって行う必要があります。不変の状態により、どのスレッドからでも簡単かつ安全に使用でき、複数のスレッドが存在する場合の正確性が保証されます。」

しかし、UI がタスクの完了後にのみオブジェクトに触れる場合は、問題ないはずですよね?

4

2 に答える 2

6

サービスには、サービスの提供されたタスクから返されるオブジェクトの型を指定するために使用されるジェネリック型パラメーターである署名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();

これを試すために使用できる実行可能なサンプルをいくつか作成しました。

于 2013-01-05T02:09:37.480 に答える
2

プロパティは、単純な型に対してのみ定義されているようです。StringProperty、IntegerProperty、DoubleProperty など。現在、Task で操作し、生成された出力データで更新するユーザー定義オブジェクト (単純な型ではない) があります。

独自のクラスに使用できるプロパティが必要な場合は、SimpleObjectProperty (T は Exception など) を試してください。

また、タスクの操作中に例外がスローされた場合、サービスから UI にどのように渡されますか?

UI から Task#onFailedProperty に EventHandler を設定し、失敗時に何をすべきかのロジックを設定できます。

しかし、UI がタスクの完了後にのみオブジェクトに触れる場合は、問題ないはずですよね?

UI から呼び出す場合は、必ず javaFX スレッドにいるので問題ありません。Platform.isFxApplicationThread() を呼び出すことで、javaFX スレッドにいることをアサートできます。

于 2013-01-05T00:09:17.617 に答える