0

I am developing a game of Quiz, with a web server and a client. Now, when the client connects to the server, it crashes. The reason is that code which takes a long time to run, should be executed on a background thread and not on the FX Application Thread. This means that I have to:

  • Create a task, that handles the data from the web server.
  • Register a handler that sends the results to the UI when it's complete.
  • Invoke the task on a background thread.

But I how do I do this when it's a runnable method that is handling the input from the server? I am trying to implement the tutorial that you can find at Using threads to make database requests

The problems occur when I am coming to this part of the code:

         Task<Runnable> clientTask = new Task<Runnable>() {
             @Override
             public Client call() throws Exception {
                 return (Client) clientRunner;
             }
         };
         clientTask.setOnSucceeded(e ->
         Runnable clientRunner = clientTask.getValue();   //Cannot resolve symbol 'setOnsucceded' 

         executor.execute(clientTask); //Cannot resolve symbol 'executor' and unknow class clientTask 

     };
 }

The Client Class:

 package sample;

 import javafx.application.Platform;
 import javafx.concurrent.Task;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
 import javafx.scene.control.TextArea;
 import javafx.scene.control.TextField;
 import java.io.*;
 import java.net.Socket;
 import java.util.Scanner;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import static java.util.concurrent.Executors.newCachedThreadPool;
 import static sun.management.snmp.jvminstr.JvmThreadInstanceEntryImpl.ThreadStateMap.Byte0.runnable;

 public class Client implements Runnable {
  @FXML
  private TextArea Out = new TextArea();
  @FXML
  private TextField Input = new TextField();

  String alias;
  String ServerAddress = "localhost";
  String userAnswer;
  BufferedReader reader;
  PrintWriter writer;

  @FXML
  public void initialize() {
   bQuit.setOnAction(event -> Platform.exit());

   aliasField.setOnAction(a -> {
    alias = aliasField.getText();
    Input.setOnAction(b -> {
     userAnswer = Input.getText();
    });
   });
   aliasField.setPromptText("Alias");
   Input.setPromptText("And your answer is:");
   IP.setPromptText("IP to the server");

   ExecutorService executor = Executors.newCachedThreadPool(runnable -> {
    Thread t = new Thread(runnable);
    t.setDaemon(true);
    return t;
   });
  }

  Runnable clientRunner = new Runnable() {
   @Override
   public void run() {

    try {
     Socket clientSocket = new Socket(ServerAddress, 9001);
     reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
     writer = new PrintWriter(clientSocket.getOutputStream(), true); 
     Scanner newObject = new Scanner(reader);

     while (newObject.hasNextLine())
      Out.appendText(newObject.next() + "");
    } catch (IOException e) {
     System.out.println("Something isn't working as intended =(");
    }
   }
   Task < Runnable > clientTask = new Task < Runnable > () {
    @Override
    public Client call() throws Exception {
     return (Client) clientRunner;
    }
   };
    clientTask.setOnSucceeded(e ->
     Runnable clientRunner = clientTask.getValue();       //Cannot resolve symbol 'setOnsucceded' 

executor.execute(clientTask);                               //Cannot resolve symbol 'executor' and unknow class clientTask 
   };
  }
Community
  • 1
  • 1
Josef Lundström
  • 197
  • 2
  • 15
  • As far as I can tell, `clientTask.setOnSucceeded(...)` isn't even inside a method definition. And `executor` appears to be defined locally to the `initialize()` method. It's not really clear how this is supposed to work, anyway: your task's `call()` method returns immediately, returning a `Runnable` (so there seems to be no point in using a task at all): you then execute the `Runnable` when the task is complete (immediately after it is launched). But then the runnable's run method, which is executed on a background thread, tries to update the UI (which is not allowed). – James_D Apr 05 '17 at 13:32
  • 1
    Why not just do `executor.execute(clientRunner);` in the initialize method, and wrap the call to `out.appendText(...)` in `Platform.runLater(...)`. Then just get rid of the redundant task entirely. – James_D Apr 05 '17 at 13:34
  • Thank you for your suggestion, but I am unsure how to do this! – Josef Lundström Apr 05 '17 at 14:21

0 Answers0