Как сообщить определенные пользователем объекты и исключения между сервисом и пользовательским интерфейсом в JavaFX2?

Как связывать определенные пользователем объекты и определенные пользователем (отмеченные) исключения между сервисом и пользовательским интерфейсом в JavaFX2? В примерах показано, что String отправляется Службе как свойство, а массив наблюдаемых строк отправляется обратно в пользовательский интерфейс.

Свойства, по-видимому, определяются только для простых типов. StringProperty, IntegerProperty, ************** и т.д. В настоящее время у меня есть определенный пользователем объект (не простой тип), который я хочу, чтобы Task работал и обновлял выходные данные, которые он произвел. Я отправляю его через конструктор Службы, который передает его через конструктор задачи. Я задавался вопросом о том, что параметры должны передаваться через свойства. Кроме того, если во время операции "Задача" возникает исключение, как это будет передаваться из Сервиса в пользовательский интерфейс? Я вижу только метод getException(), не традиционный throw/catch.

Свойства http://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm

Сервис и задача http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

Сервис javadocs http://docs.oracle.com/javafx/2/api/javafx/concurrent/Service.html#getException()

"Поскольку задача предназначена для использования с приложениями GUI JavaFX, она гарантирует, что каждое изменение его публичных свойств, а также изменение уведомления о состоянии, ошибках и обработчиках событий, все основной поток приложений JavaFX. Доступ к этим свойствам из фоновый поток (включая метод call()) приведет к времени выполнения исключения.

Настоятельно рекомендуется, чтобы все Задачи были инициализированы неизменными состояние, на которое будет действовать Задача. Это должно быть сделано предоставляя конструктор задачи, который принимает параметры, необходимые для выполнение Задачи. Неизменное состояние позволяет легко и безопасно использовать из любого потока и обеспечивает правильность в присутствии нескольких нити".

Но если мой пользовательский интерфейс касается только объекта после выполнения задачи, тогда он должен быть в порядке, правильно?

2 ответа

Сервис имеет подпись Service - это параметр общего типа, используемый для указания типа возвращаемого объекта из поставленной службы.

Предположим, вы хотите определить службу, которая возвращает определенный пользователем объект типа Foo, тогда вы можете сделать это следующим образом:

class FooGenerator extends Service<foo> {
 protected Task createTask() {
 return new Task<foo>() {
 protected Foo call() throws Exception {
 return new Foo();
 }
 };
 }
 }
</foo></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();
</workerstateevent>

Если вы хотите передать входное значение в службу каждый раз перед запуском или перезапуском, вы должны быть немного более осторожны. Вы можете добавить значения, которые хотите ввести в службу, в качестве настраиваемых членов службы. Эти сеттеры можно вызывать из потока приложений JavaFX до того, как вызывается метод запуска службы. Затем, когда создается служебная задача, передайте параметры в конструктор задачи Service.

При этом лучше всего сделать всю информацию проходимой вперед и назад между неизменными нитями. В приведенном ниже примере объект 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; }
}
</foo></foo>

Существует еще один пример предоставления ввода 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();
 }
 };
 }
 }
</foo></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();
</workerstateevent>

Я создал пару исполняемых образцов, которые вы можете использовать, чтобы попробовать это.


Свойства, по-видимому, определяются только для простых типов. StringProperty, IntegerProperty, ************** и т.д. В настоящее время у меня есть пользовательский объект (не простой тип), который я хочу, чтобы Task работал и обновлялся с выходными данными, которые он произвел

Если вы хотите, чтобы свойство, которое можно было использовать для ваших собственных классов, попробуйте SimpleObjectProperty, где T может быть Исключением или тем, что вам нужно.

Кроме того, если во время операции "Задача" возникает исключение, как это будет передаваться из Сервиса в пользовательский интерфейс?

Вы можете установить EventHandler в Task # onFailedProperty из пользовательского интерфейса с логикой, что делать с ошибкой.

Но если мой пользовательский интерфейс касается только объекта после выполнения задачи, тогда он должен быть в порядке, правильно?

Если вы вызываете это из своего пользовательского интерфейса, вы обязательно будете в потоке javaFX, так что все будет в порядке. Вы можете утверждать, что вы находитесь в потоке javaFX, вызывая Platform.isFxApplicationThread().

licensed under cc by-sa 3.0 with attribution.