0

This is the main window of my application:

screenshot

I want to be able to update the window, so i wrote a method reset which ist triggered by pressing F5:

public void reset() {
    final ProgressIndicator pi = new ProgressIndicator(-1.0f);

    final HBox hb = new HBox(pi);
    final VBox vb = new VBox(hb);

    hb.setAlignment(Pos.CENTER);
    vb.setAlignment(Pos.CENTER);

    scene.setRoot(vb);

    //this.show();
}

if i run this it looks sth like this:

screenshot

However, if I uncomment the line //this.show(); this will be executed:

public void show() {
    final VBox box = API_CALL_AND_BUILDING_BOX_MAGIC_WHICH_I_STRIPPED;

    gp.getChildren().clear();
    gp.getChildren().add(box);

    scene.setRoot(gp);
    stage.sizeToScene();
}

and I will never be able to see my ProgressIndicator because the application will just hang until the APIcall is finished and the new content is loaded.

I tried a bit with Threads and Platform.runLater() but I cant get it to work. My goal is to display the ProgressIndicator until the APIcall is finished, the box is build and the scene gets given gp as the new root.

I hope its somewhat understandable what my goal and my problems are :)

daputzy
  • 45
  • 1
  • 6

1 Answers1

1

You need to create another JVM thread dedicated to fetch data from the remote source. The main thread of your application must never block with network operations: in the keyboard event handler you just repaint the main window with the progress indicator and then wait for another event, that can be:

  • background operation finished (successful, unsuccessful)
  • user interrupts (mouse/keyboard)
  • a timeout expires

Pseudocode with ListenableFuture by Guava

// Initialize in ctor use MoreExecutors
private final ListeningExecutorService service;

// Keep to call .cancel()
private ListenableFuture<APIData> currentRequest;

// Run in the GUI thread
public void onRefreshEvent() {
  showProgressIndicator();
  currentRequest = service.submit(/* Some Callable<APIData> */);
  Futures.addCallback(currentRequest , this, this);
}

// From FutureCallback<T>
public void onFailure(Throwable t) {} // TODO
public void onSuccess(APIData d) {}   // TODO

// From Executor
public void execute(Runnable cmd) {
  Platform.runLater(cmd);
}

Don't forget to consider socket connect and read timeout, as well as pooling HTTP connection! Also consider if the background task should check the interrupted flag

Raffaele
  • 20,627
  • 6
  • 47
  • 86
  • FFS how can I create a new line in a comment? :D – daputzy Jan 13 '16 at 18:30
  • Ahh its shift + enter... So what i wanted to say: I got it to work, even though on a much more basic level then you suggested. You're obviously operating some levels above me ;) But I will now try to implement it they way you suggested! – daputzy Jan 13 '16 at 18:32
  • 1
    Note that since this is a JavaFX question, the JavaFX API defines a specific [`Task`](http://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html) class for this purpose; it provides an `updateProgress` method and other callback methods for interacting with the UI thread. – James_D Jan 13 '16 at 18:37