0

I'm here for the third time, this time about the threading within JavaFX.

So, I'm trying to have a loading screen, and the loadingscreen has a controller which is used as interface (NOT ACTUAL INTERFACE) between the entry and the result.

Here is the code:

private void createLoadingScreenScene(String id) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/lollookup/scene/loadingscreen/loadingscreen.fxml"));
        Stage stage = new Stage(StageStyle.DECORATED);
        stage.setScene(new Scene(loader.load()));
        stage.show();
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                LoadingScreenController controller = loader.getController();
                controller.setSummoner(lookupTextField.getText(), regionsBox.getSelectionModel().getSelectedItem());
                switch (id.toLowerCase()) {
                    case "ag_lookup":
                        controller.loadActiveGame();
                        break;
                    case "sum_lookup":
                        controller.loadProfile();
                        break;
                }
                return null;
            }
        };
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<?> submit = executorService.submit(task);
    }

everything works perfectly fine until this: assuming the id is sum_lookup this method gets executed:

public void loadProfile() {
        if (summoner != null) {
            try {
                System.out.println("Loading profile scene");
                createProfileScene();
            } catch (DataException | WrongRequestFormatException | ReplyException | IOException e) {
                e.printStackTrace();
            }
        }
    }

And createProfileScene is the following:

private void createProfileScene() throws IOException, DataException, WrongRequestFormatException, ReplyException {
    System.out.println("Going ham..");
    String summonerName = summoner.getName();
    System.out.println("Going ham..0.5");
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/lollookup/scene/summonerlookup/profile.fxml"));
    System.out.println("Going ham.. 0.8");
    Stage stage = new Stage(StageStyle.DECORATED);
    System.out.println("Going ham..1");
    stage.setScene(new Scene(loader.load()));
    ProfileController controller = loader.getController();
    List<ChampionMastery> championMasteries = leagueAPI.getChampionMasteries(summoner.getId()); //TODO here
    System.out.println("Going ham..2");
    stage.show()

Now everything works until "Going ham 0.8" is being printed. The program literally stops outputting data.

That's the output:

Loading profile scene
Going ham..
Going ham..0.5
Going ham.. 0.8

What am i doing wrong?

EDIT:

Thats the code I now changed: private void createLoadingScreenScene(String id) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/lollookup/scene/loadingscreen/loadingscreen.fxml")); Stage stage = new Stage(StageStyle.DECORATED); stage.setScene(new Scene(loader.load())); LoadingScreenController controller = loader.getController(); controller.setSummoner(lookupTextField.getText(), regionsBox.getSelectionModel().getSelectedItem()); switch (id.toLowerCase()) { case "ag_lookup": controller.loadActiveGame();

        case "sum_lookup":
            controller.loadProfile();

    }
    stage.show();
}

This is the actual task which takes heavy load of time: (now in a Task)

Task task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            System.out.println("Going ham..");
            String summonerName = summoner.getName();
            System.out.println("Going ham..0.5");
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/lollookup/scene/summonerlookup/profile.fxml"));
            System.out.println("Going ham.. 0.8");
            Stage stage = new Stage(StageStyle.DECORATED);
            System.out.println("Going ham..1");
            stage.setScene(new Scene(loader.load()));
            ProfileController controller = loader.getController();
            List<ChampionMastery> championMasteries = leagueAPI.getChampionMasteries(summoner.getId()); //TODO unused
            System.out.println("Going ham..2");
            ChampionInfoData[] championStatsSummary = leagueAPI.getChampionStatsRanked(summoner.getId(), Season.SEASON_7).getChampionStatsSummary().stream().filter(element -> element.getId() != 0).map(element -> {
                try {
                    ChampionStats championStats = element.getChampionStats();
                    int championId = element.getId();
                    return new ChampionInfoData(leagueAPI.getImageUrl(championId), leagueAPI.getChampionData(championId).getName(), championStats.displayAverageKDA(), championStats.displayWinrate(), championStats.displayAverageCreepScore(), "0");
                } catch (ReplyException | DataException | IOException | WrongRequestFormatException e) {
                    e.printStackTrace();
                }
                return null;
            }).toArray(ChampionInfoData[]::new);
            System.out.println("Did i come this far? Yes!" + championStatsSummary.length);
            controller.createProfile(new SummonerData("http://avatar.leagueoflegends.com/" + summoner.getRegion().getShortCode() + "/" + summonerName.replace(" ", "") + ".png", summonerName, String.valueOf(summoner.getSummonerLevel())), championStatsSummary);
            stage.show();
            return null;
        }
    };
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.submit(task);

Yet the output still is:

Loading profile scene
Going ham..
Going ham..0.5
Going ham.. 0.8
Sh0ck
  • 97
  • 2
  • 12
  • Read the [documentation for the `Stage` constructor you are calling](http://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html#Stage--). Why are you running this on a background thread - which code takes a long time to run? – James_D Mar 29 '17 at 14:38
  • I'm running it on a background thread so i can actually run a GIF on the loadingscreen scene (if i just put it in there with no task created at all it'll just be a white screen then the new scene opens when it finished loading) – Sh0ck Mar 29 '17 at 14:55
  • And what do you mean with reading the documentation for the Stage constructor im calling? I can't tell what this has anything to do with my problem – Sh0ck Mar 29 '17 at 15:00
  • 1
    The question about why you're using a background thread was asking if there is actually any code run in the background thread that takes an appreciable amount of time. If so, which code is it? That code, and *only* that code, should be on the background thread (so what is happening while you show your image?). As for the documentation, there are only two sentences, the second of which is: *"Throws `IllegalStateException` if this constructor is called on a thread other than the JavaFX Application Thread"* – James_D Mar 29 '17 at 15:03
  • I don't get any error thrown. And updated the question (in context with your question about the background task) – Sh0ck Mar 29 '17 at 15:15
  • Sure you get an exception, you just don't see the stack trace (why would you?). – James_D Mar 29 '17 at 15:16
  • OK, you completely misunderstood my question, I guess. We have no idea what `summoner.getName()` or `leagueAPI.getChampionshipMasteries()` etc etc are doing. Maybe they are simply returning the value of a variable, or maybe they are retrieving data over a network connection, parsing it, and doing other time-consuming operations. Other parts of your task definitely don't take a long time (e.g. `FXMLLoader loader = new FXMLLoader(...)`), and the code at the point where it fails is documented to throw an exception if called in a thread other than the FX Application Thread. – James_D Mar 29 '17 at 15:23
  • So you need to divide this up so that the time-consuming code is called in the background thread, and the UI code is called in the FX Application Thread. But no-one except you has the information to know how that division should happen. – James_D Mar 29 '17 at 15:23
  • OH. Wait, I got it. Hang on a second – Sh0ck Mar 29 '17 at 15:25
  • You are calling `new Stage(...)` in your `call()` method, so you are explicitly calling it in a background thread. It's an unchecked exception, it's thrown in that thread, you don't catch it, so the method and consequently the thread just terminate there. Wrap the call to `new Stage(...)` in a `try` with `catch (Exception exc) { exc.printStackTrace();}` and you will see the stack trace. – James_D Mar 29 '17 at 15:25
  • I GOT IT! I got your point, I wrapped the network-intensive code in a Task, whilst excluding the Scene initialisement part on the fx-thread. Thank you, can you post an answer so I can mark it as the correct answer? – Sh0ck Mar 29 '17 at 15:28

0 Answers0