Service 在JavaFX2中,如何在服务和UI之间传递用户定义的对象和异常?

Service 在JavaFX2中,如何在服务和UI之间传递用户定义的对象和异常?,service,javafx-2,worker,Service,Javafx 2,Worker,在JavaFX2中,如何在服务和UI之间传递用户定义对象和用户定义(检查)异常? 这些示例仅显示作为属性发送到服务的字符串和发送回UI的可观察字符串数组 属性似乎只为简单类型定义。StringProperty、IntegerProperty、DoubleProperty等。 目前,我有一个用户定义的对象(不是简单的类型),我希望Task对其进行操作,并使用它生成的输出数据进行更新。我通过服务的构造函数发送它,服务的构造函数通过任务的构造函数传递它。我想知道参数必须通过属性传入的限制。 另外,如果

在JavaFX2中,如何在服务和UI之间传递用户定义对象和用户定义(检查)异常? 这些示例仅显示作为属性发送到服务的字符串和发送回UI的可观察字符串数组

属性似乎只为简单类型定义。StringProperty、IntegerProperty、DoubleProperty等。 目前,我有一个用户定义的对象(不是简单的类型),我希望Task对其进行操作,并使用它生成的输出数据进行更新。我通过服务的构造函数发送它,服务的构造函数通过任务的构造函数传递它。我想知道参数必须通过属性传入的限制。 另外,如果在任务的操作过程中引发异常,如何将其从服务传递到UI?我只看到一个getException()方法,没有传统的抛出/捕获

性质

服务与任务

服务javadocs()

“由于该任务设计用于JavaFXGUI应用程序,因此 确保对其公共属性的每次更改以及 状态、错误和事件处理程序的通知都发生在 主JavaFX应用程序线程。从 后台线程(包括call()方法)将导致运行时 提出的例外情况

强烈建议使用immutable初始化所有任务 任务将在其上运行的状态。这应由 提供一个任务构造函数,该构造函数接受 任务的执行。不可变状态使其易于安全使用 从任何线程,并确保在存在多个线程时的正确性 线程。”

但是如果我的UI只在任务完成后才接触对象,那么它应该是正常的,对吗

属性似乎只为简单类型定义。StringProperty、IntegerProperty、DoubleProperty等。目前,我有一个用户定义的对象(不是简单的类型),我希望Task对其进行操作,并使用它生成的输出数据进行更新

如果您想要一个可用于您自己的类的属性,请尝试SimpleObjectProperty,其中T可以是Exception,或者您需要的任何属性

另外,如果在任务的操作过程中引发异常,如何将其从服务传递到UI

您可以在UI中的Task#onFailedProperty上设置EventHandler,该属性具有失败时要执行的操作的逻辑

但是如果我的UI只在任务完成后才接触对象,那么它应该是正常的,对吗


如果您从UI调用它,那么您肯定在javaFX线程上,这样您就可以了。通过调用Platform.isFxApplicationThread(),您可以断言您在javaFX线程上。

服务有一个签名
服务
是一个泛型类型参数,用于指定服务提供的任务中返回对象的类型

假设您想要定义一个返回用户定义的Foo类型对象的服务,那么您可以这样做:

 class FooGenerator extends Service<Foo> {
   protected Task createTask() {
     return new Task<Foo>() {
       protected Foo call() throws Exception {
         return new Foo();
       }
     };
   }
 }
 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();
可以如下方式检索异常:

 class FooGenerator extends Service<Foo> {
   protected Task createTask() {
     return new Task<Foo>() {
       protected Foo call() throws Exception {
         return new Foo();
       }
     };
   }
 }
 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();
BadFooGenerator BadFooGenerator=new BadFooGenerator();
badFooGenerator.setOnFailed(新的EventHandler(){
@重写公共无效句柄(WorkerStateT事件){
Throwable ouch=badFooGenerator.getException();
System.out.println(ouch.getClass().getName()+“->”+ouch.getMessage());
}
});
badFooGenerator.start();


我创建了两个工具,您可以使用它们来尝试这一点。

假设我想从UI向FooGenerator传递一个Foo。我可以简单地创建一个成员变量Foo foo2;在服务中,然后从UI设置它?setFoo(f)。特别是在线程安全方面可以吗?谢谢你的回复。我还有第二个问题。在类
FooGenerator extensed Service
中,我可以说
Service
并在
return new Task()
中,然后在
call()
中执行
return Foo
?我向服务添加了一些关于输入参数的信息,以显示如何使用Foo对象作为输入。关于
服务
,您可以这样做,但如果您只想在服务可以返回多种类型的数据时这样做,即如果您知道该服务总是返回一个Foo,则将其定义为
服务
,但如果该服务可以返回Foo或Bah,然后将其定义为
Service
,并检查返回对象的类型,查看是否有Foo或Bah。是的,我想返回Foo列表和字符串。感谢您对输入参数的澄清。如果我知道UI和任务不会同时修改它,为什么Foo必须是不可变的?Foo不一定是不可变的。在我看来,如果是这样的话,就更容易对该计划进行推理。如果您可以使用可变的Foo编写线程安全的程序,并且您更愿意这样做,那么就这样做。服务不必返回ObservableList(如我的示例代码所示)。我不知道为什么会如此推荐属性。如果在后台线程上运行服务,我看不出它们有多有用。它返回的结果无论如何都会更新UI。谢谢你提供的断言信息。我同意属性在某些情况下没有多大帮助,比如任务。但是,如果使用POJO getter和setter,则可以在不破坏代码的情况下将普通字段作为属性。
 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();