< prev index next >

modules/graphics/src/main/java/javafx/concurrent/Task.java

Print this page




  60  *     A fully observable implementation of a {@link FutureTask}. {@code Task} exposes
  61  *     additional state and observable properties useful for programming asynchronous
  62  *     tasks in JavaFX, as defined in the {@link Worker} interface. An implementation
  63  *     of Task must override the {@link javafx.concurrent.Task#call()} method. This method
  64  *     is invoked on the background thread. Any state which is used in this method
  65  *     must be safe to read and write from a background thread. For example, manipulating
  66  *     a live scene graph from this method is unsafe and will result in runtime
  67  *     exceptions.
  68  * </p>
  69  * <p>
  70  *     Tasks are flexible and extremely useful for the encapsulation of "work". Because
  71  *     {@link Service} is designed to execute a Task, any Tasks defined by the application
  72  *     or library code can easily be used with a Service. Likewise, since Task extends
  73  *     from FutureTask, it is very easy and natural to use a Task with the java concurrency
  74  *     {@link java.util.concurrent.Executor} API. Since a Task is Runnable, you
  75  *     can also call it directly (by invoking the {@link javafx.concurrent.Task#run()} method)
  76  *     from another background thread. This allows for composition of work, or pass it to
  77  *     a new Thread constructed and executed manually. Finally, since you can
  78  *     manually create a new Thread, passing it a Runnable, it is possible to use
  79  *     the following idiom:

  80  *     <pre><code>
  81  *         Thread th = new Thread(task);
  82  *         th.setDaemon(true);
  83  *         th.start();
  84  *     </code></pre>

  85  *     Note that this code sets the daemon flag of the Thread to true. If you
  86  *     want a background thread to prevent the VM from existing after the last
  87  *     stage is closed, then you would want daemon to be false. However, if
  88  *     you want the background threads to simply terminate after all the
  89  *     stages are closed, then you must set daemon to true.
  90  * </p>
  91  * <p>
  92  *     Although {@link java.util.concurrent.ExecutorService} defines several methods which
  93  *     take a Runnable, you should generally limit yourself to using the <code>execute</code>
  94  *     method inherited from {@link java.util.concurrent.Executor}.
  95  * </p>
  96  * <p>
  97  *     As with FutureTask, a Task is a one-shot class and cannot be reused. See {@link Service}
  98  *     for a reusable {@link Worker}.
  99  * </p>
 100  * <p>
 101  *     Because the Task is designed for use with JavaFX GUI applications, it ensures
 102  *     that every change to its public properties, as well as change notifications
 103  *     for state, errors, and for event handlers, all occur on the main JavaFX application
 104  *     thread. Accessing these properties from a background thread (including the


 426  *             // Return null at the end of a Task of type Void
 427  *             return null;
 428  *         }
 429  *     };
 430  * </code></pre>
 431  *
 432  * <h3>A Task Which Returns An ObservableList</h3>
 433  *
 434  * <p>Because the ListView, TableView, and other UI controls and scene graph
 435  * nodes make use of ObservableList, it is common to want to create and return
 436  * an ObservableList from a Task. When you do not care to display intermediate
 437  * values, the easiest way to correctly write such a Task is simply to
 438  * construct an ObservableList within the <code>call</code> method, and then
 439  * return it at the conclusion of the Task.</p>
 440  *
 441  * <pre><code>
 442  *     Task&lt;ObservableList&lt;Rectangle&gt;&gt; task = new Task&lt;ObservableList&lt;Rectangle&gt;&gt;() {
 443  *         @Override protected ObservableList&lt;Rectangle&gt; call() throws Exception {
 444  *             updateMessage("Creating Rectangles");
 445  *             ObservableList&lt;Rectangle&gt; results = FXCollections.observableArrayList();
 446  *             for (int i=0; i<100; i++) {
 447  *                 if (isCancelled()) break;
 448  *                 Rectangle r = new Rectangle(10, 10);
 449  *                 r.setX(10 * i);
 450  *                 results.add(r);
 451  *                 updateProgress(i, 100);
 452  *             }
 453  *             return results;
 454  *         }
 455  *     };
 456  * </code></pre>
 457  *
 458  * <p>In the above example, we are going to create 100 rectangles and return
 459  * them from this task. An ObservableList is created within the
 460  * <code>call</code> method, populated, and then returned.</p>
 461  *
 462  * <h3>A Task Which Returns Partial Results</h3>
 463  *
 464  * <p>Sometimes you want to create a Task which will return partial results.
 465  * Perhaps you are building a complex scene graph and want to show the
 466  * scene graph as it is being constructed. Or perhaps you are reading a large


 506  *                         updateValue(v);
 507  *                     }
 508  *                 }
 509  *                 a += b;
 510  *                 b = a - b;
 511  *             }
 512  *             return a;
 513  *         }
 514  *     };
 515  * </code></pre>
 516  *
 517  * <p>Suppose instead of updating a single value, you want to populate an ObservableList
 518  * with results as they are obtained. One approach is to expose a new property on the Task
 519  * which will represent the partial result. Then make sure to use
 520  * <code>Platform.runLater</code> when adding new items to the partial
 521  * result.</p>
 522  *
 523  * <pre><code>
 524  *     public class PartialResultsTask extends Task&lt;ObservableList&lt;Rectangle&gt;&gt; {
 525  *         // Uses Java 7 diamond operator
 526  *         private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults =
 527  *                 new ReadOnlyObjectWrapper<>(this, "partialResults",
 528  *                         FXCollections.observableArrayList(new ArrayList<Rectangle>()));
 529  *
 530  *         public final ObservableList<Rectangle> getPartialResults() { return partialResults.get(); }
 531  *         public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty() {
 532  *             return partialResults.getReadOnlyProperty();
 533  *         }
 534  *
 535  *         @Override protected ObservableList<Rectangle> call() throws Exception {
 536  *             updateMessage("Creating Rectangles...");
 537  *             for (int i=0; i<100; i++) {
 538  *                 if (isCancelled()) break;
 539  *                 final Rectangle r = new Rectangle(10, 10);
 540  *                 r.setX(10 * i);
 541  *                 Platform.runLater(new Runnable() {
 542  *                     @Override public void run() {
 543  *                         partialResults.get().add(r);
 544  *                     }
 545  *                 });
 546  *                 updateProgress(i, 100);
 547  *             }
 548  *             return partialResults.get();
 549  *         }
 550  *     }
 551  * </code></pre>
 552  *
 553  * <h3>A Task Which Modifies The Scene Graph</h3>
 554  *
 555  * <p>Generally, Tasks should not interact directly with the UI. Doing so
 556  * creates a tight coupling between a specific Task implementation and a
 557  * specific part of your UI. However, when you do want to create such a
 558  * coupling, you must ensure that you use <code>Platform.runLater</code>
 559  * so that any modifications of the scene graph occur on the
 560  * FX Application Thread.</p>
 561  *
 562  * <pre><code>
 563  *     final Group group = new Group();
 564  *     Task&lt;Void&gt; task = new Task&lt;Void&gt;() {
 565  *         @Override protected Void call() throws Exception {
 566  *             for (int i=0; i<100; i++) {
 567  *                 if (isCancelled()) break;
 568  *                 final Rectangle r = new Rectangle(10, 10);
 569  *                 r.setX(10 * i);
 570  *                 Platform.runLater(new Runnable() {
 571  *                     @Override public void run() {
 572  *                         group.getChildren().add(r);
 573  *                     }
 574  *                 });
 575  *             }
 576  *             return null;
 577  *         }
 578  *     };
 579  * </code></pre>
 580  *
 581  * <h3>Reacting To State Changes Generically</h3>
 582  *
 583  * <p>Sometimes you may want to write a Task which updates its progress,
 584  * message, text, or in some other way reacts whenever a state change
 585  * happens on the Task. For example, you may want to change the status
 586  * message on the Task on Failure, Success, Running, or Cancelled state changes.




  60  *     A fully observable implementation of a {@link FutureTask}. {@code Task} exposes
  61  *     additional state and observable properties useful for programming asynchronous
  62  *     tasks in JavaFX, as defined in the {@link Worker} interface. An implementation
  63  *     of Task must override the {@link javafx.concurrent.Task#call()} method. This method
  64  *     is invoked on the background thread. Any state which is used in this method
  65  *     must be safe to read and write from a background thread. For example, manipulating
  66  *     a live scene graph from this method is unsafe and will result in runtime
  67  *     exceptions.
  68  * </p>
  69  * <p>
  70  *     Tasks are flexible and extremely useful for the encapsulation of "work". Because
  71  *     {@link Service} is designed to execute a Task, any Tasks defined by the application
  72  *     or library code can easily be used with a Service. Likewise, since Task extends
  73  *     from FutureTask, it is very easy and natural to use a Task with the java concurrency
  74  *     {@link java.util.concurrent.Executor} API. Since a Task is Runnable, you
  75  *     can also call it directly (by invoking the {@link javafx.concurrent.Task#run()} method)
  76  *     from another background thread. This allows for composition of work, or pass it to
  77  *     a new Thread constructed and executed manually. Finally, since you can
  78  *     manually create a new Thread, passing it a Runnable, it is possible to use
  79  *     the following idiom:
  80  * </p>
  81  *     <pre><code>
  82  *         Thread th = new Thread(task);
  83  *         th.setDaemon(true);
  84  *         th.start();
  85  *     </code></pre>
  86  * <p>
  87  *     Note that this code sets the daemon flag of the Thread to true. If you
  88  *     want a background thread to prevent the VM from existing after the last
  89  *     stage is closed, then you would want daemon to be false. However, if
  90  *     you want the background threads to simply terminate after all the
  91  *     stages are closed, then you must set daemon to true.
  92  * </p>
  93  * <p>
  94  *     Although {@link java.util.concurrent.ExecutorService} defines several methods which
  95  *     take a Runnable, you should generally limit yourself to using the <code>execute</code>
  96  *     method inherited from {@link java.util.concurrent.Executor}.
  97  * </p>
  98  * <p>
  99  *     As with FutureTask, a Task is a one-shot class and cannot be reused. See {@link Service}
 100  *     for a reusable {@link Worker}.
 101  * </p>
 102  * <p>
 103  *     Because the Task is designed for use with JavaFX GUI applications, it ensures
 104  *     that every change to its public properties, as well as change notifications
 105  *     for state, errors, and for event handlers, all occur on the main JavaFX application
 106  *     thread. Accessing these properties from a background thread (including the


 428  *             // Return null at the end of a Task of type Void
 429  *             return null;
 430  *         }
 431  *     };
 432  * </code></pre>
 433  *
 434  * <h3>A Task Which Returns An ObservableList</h3>
 435  *
 436  * <p>Because the ListView, TableView, and other UI controls and scene graph
 437  * nodes make use of ObservableList, it is common to want to create and return
 438  * an ObservableList from a Task. When you do not care to display intermediate
 439  * values, the easiest way to correctly write such a Task is simply to
 440  * construct an ObservableList within the <code>call</code> method, and then
 441  * return it at the conclusion of the Task.</p>
 442  *
 443  * <pre><code>
 444  *     Task&lt;ObservableList&lt;Rectangle&gt;&gt; task = new Task&lt;ObservableList&lt;Rectangle&gt;&gt;() {
 445  *         @Override protected ObservableList&lt;Rectangle&gt; call() throws Exception {
 446  *             updateMessage("Creating Rectangles");
 447  *             ObservableList&lt;Rectangle&gt; results = FXCollections.observableArrayList();
 448  *             for (int i=0; i&lt;100; i++) {
 449  *                 if (isCancelled()) break;
 450  *                 Rectangle r = new Rectangle(10, 10);
 451  *                 r.setX(10 * i);
 452  *                 results.add(r);
 453  *                 updateProgress(i, 100);
 454  *             }
 455  *             return results;
 456  *         }
 457  *     };
 458  * </code></pre>
 459  *
 460  * <p>In the above example, we are going to create 100 rectangles and return
 461  * them from this task. An ObservableList is created within the
 462  * <code>call</code> method, populated, and then returned.</p>
 463  *
 464  * <h3>A Task Which Returns Partial Results</h3>
 465  *
 466  * <p>Sometimes you want to create a Task which will return partial results.
 467  * Perhaps you are building a complex scene graph and want to show the
 468  * scene graph as it is being constructed. Or perhaps you are reading a large


 508  *                         updateValue(v);
 509  *                     }
 510  *                 }
 511  *                 a += b;
 512  *                 b = a - b;
 513  *             }
 514  *             return a;
 515  *         }
 516  *     };
 517  * </code></pre>
 518  *
 519  * <p>Suppose instead of updating a single value, you want to populate an ObservableList
 520  * with results as they are obtained. One approach is to expose a new property on the Task
 521  * which will represent the partial result. Then make sure to use
 522  * <code>Platform.runLater</code> when adding new items to the partial
 523  * result.</p>
 524  *
 525  * <pre><code>
 526  *     public class PartialResultsTask extends Task&lt;ObservableList&lt;Rectangle&gt;&gt; {
 527  *         // Uses Java 7 diamond operator
 528  *         private ReadOnlyObjectWrapper&lt;ObservableList&lt;Rectangle&gt;&gt; partialResults =
 529  *                 new ReadOnlyObjectWrapper&lt;&gt;(this, "partialResults",
 530  *                         FXCollections.observableArrayList(new ArrayList&lt;Rectangle&gt;()));
 531  *
 532  *         public final ObservableList&lt;Rectangle&gt; getPartialResults() { return partialResults.get(); }
 533  *         public final ReadOnlyObjectProperty&lt;ObservableList&lt;Rectangle&gt;&gt; partialResultsProperty() {
 534  *             return partialResults.getReadOnlyProperty();
 535  *         }
 536  *
 537  *         @Override protected ObservableList&lt;Rectangle&gt; call() throws Exception {
 538  *             updateMessage("Creating Rectangles...");
 539  *             for (int i=0; i&lt;100; i++) {
 540  *                 if (isCancelled()) break;
 541  *                 final Rectangle r = new Rectangle(10, 10);
 542  *                 r.setX(10 * i);
 543  *                 Platform.runLater(new Runnable() {
 544  *                     @Override public void run() {
 545  *                         partialResults.get().add(r);
 546  *                     }
 547  *                 });
 548  *                 updateProgress(i, 100);
 549  *             }
 550  *             return partialResults.get();
 551  *         }
 552  *     }
 553  * </code></pre>
 554  *
 555  * <h3>A Task Which Modifies The Scene Graph</h3>
 556  *
 557  * <p>Generally, Tasks should not interact directly with the UI. Doing so
 558  * creates a tight coupling between a specific Task implementation and a
 559  * specific part of your UI. However, when you do want to create such a
 560  * coupling, you must ensure that you use <code>Platform.runLater</code>
 561  * so that any modifications of the scene graph occur on the
 562  * FX Application Thread.</p>
 563  *
 564  * <pre><code>
 565  *     final Group group = new Group();
 566  *     Task&lt;Void&gt; task = new Task&lt;Void&gt;() {
 567  *         @Override protected Void call() throws Exception {
 568  *             for (int i=0; i&lt;100; i++) {
 569  *                 if (isCancelled()) break;
 570  *                 final Rectangle r = new Rectangle(10, 10);
 571  *                 r.setX(10 * i);
 572  *                 Platform.runLater(new Runnable() {
 573  *                     @Override public void run() {
 574  *                         group.getChildren().add(r);
 575  *                     }
 576  *                 });
 577  *             }
 578  *             return null;
 579  *         }
 580  *     };
 581  * </code></pre>
 582  *
 583  * <h3>Reacting To State Changes Generically</h3>
 584  *
 585  * <p>Sometimes you may want to write a Task which updates its progress,
 586  * message, text, or in some other way reacts whenever a state change
 587  * happens on the Task. For example, you may want to change the status
 588  * message on the Task on Failure, Success, Running, or Cancelled state changes.


< prev index next >