title: Continuously update TextArea
body: <p>I'm writing a program that creates a process using youtube-dl. That process has two <code>InputStream</code>s (inputStream and errorStream) of which I want to reroute each into a text area. </p>
  
  <p>I've been trying to get the <code>TextArea</code>s to update without locking the JavaFX thread. It's working but I feel like it's terribly inefficient as it creates a large number of Task objects that only append a line. I've recreated the code I've been using below, using <code>List&lt;String&gt;</code> instead of <code>BufferedReader</code> to simplify the problem a bit.</p>
  
  <p>When I press the button it will create two threads, one for each list, with an <code>UpdateTask</code>. The UpdateTask then creates a <code>WriteTask</code> gives it to <code>Platform.runLater()</code> which places it on the JavaFX thread again.</p>
  
  <p>Surely there must be a better way to do this?</p>
  
  <pre><code>import java.util.Arrays;
  import java.util.Iterator;
  import java.util.List;
  
  import javafx.application.Platform;
  import javafx.concurrent.Task;
  import javafx.event.ActionEvent;
  import javafx.event.EventHandler;
  import javafx.scene.control.Button;
  import javafx.scene.control.TextArea;
  import javafx.scene.control.TextField;
  import javafx.scene.layout.VBox;
  
  public class ConcurrentTest extends VBox{
  
      TextArea output;
      TextArea error;
      Button start;
      TextField writable;
  
      public ConcurrentTest(){
          // Init components
          output = new TextArea();
          output.setEditable(false);
          error = new TextArea();
          error.setEditable(false);
          // Init button
          start = new Button("Print stuff");
          start.setOnAction(new EventHandler&lt;ActionEvent&gt;() {
  
              @Override
              public void handle(ActionEvent arg0) {
                  List&lt;String&gt; outputLines = Arrays.asList("A", "B", "C", "D");
                  List&lt;String&gt; errorLines = Arrays.asList("A", "B", "C", "D");;
  
                  Thread outputThread = new Thread(new UpdateTask&lt;String&gt;(output, outputLines));
                  outputThread.setDaemon(true);
                  outputThread.start();
  
                  Thread errorThread = new Thread(new UpdateTask&lt;String&gt;(error, errorLines));
                  errorThread.setDaemon(true);
                  errorThread.start();
              }
          });
          writable = new TextField();
          writable.setPromptText("Write while some text areas are getting updated.");
  
          // Add components
          this.getChildren().addAll(output, error, start, writable);
      }
  
      // UPDATE TASK CLASS
      public class UpdateTask&lt;V&gt; extends Task&lt;V&gt;{
  
          TextArea target;
          Iterator&lt;String&gt; it;
  
          public UpdateTask(TextArea target, List&lt;String&gt; lines){
              this.target = target;
              it = lines.iterator();
          }
  
          @Override
          protected V call() throws Exception {
              while(it.hasNext()){
                  Thread.sleep(1500);     // Time to type something to test
                  Platform.runLater(new WriteTask&lt;String&gt;(target, it.next()));
              }
              return null;
          }
  
      }
  
      // WRITE TASK CLASS
      public class WriteTask&lt;V&gt; extends Task&lt;V&gt;{
  
          TextArea target;
          String line;
  
          public WriteTask(TextArea target, String line) {
              this.target = target;
              this.line = line;
          }
  
          @Override
          protected V call() throws Exception {
              target.appendText(line + "\n");
              return null;
          }
      }
  }
  </code></pre>
  
  <p>For the entire program, the launcher with main:</p>
  
  <pre><code>import javafx.application.Application;
  import javafx.stage.Stage;
  import javafx.scene.Parent;
  import javafx.scene.Scene;
  
  public class ConcurrentTestLauncher extends Application {
      @Override
      public void start(Stage primaryStage) {
          try {
              Parent root = new ConcurrentTest();
              Scene scene = new Scene(root);
              primaryStage.setTitle("Concurrent FX Test");
              primaryStage.setScene(scene);
              primaryStage.show();
          } catch(Exception e) {
              e.printStackTrace();
          }
      }
  
      public static void main(String[] args) {
          launch(args);
      }
  }
  </code></pre>