How to call launch() more than once in java
Asked Answered
C

3

14

How to call the launch() more than once in java i am given an exception as "ERROR IN MAIN:java.lang.IllegalStateException: Application launch must not be called more than once"

I have create rest cleint in my java application when request comes it call javafx and opening webview after completing webview operarion am closing javafx windows using Platform.exit() method. when second request comes am getting this error how to reslove this error.

JavaFx Application Code:

public class AppWebview extends Application  {

    public static Stage stage;

    @Override
    public void start(Stage _stage) throws Exception {

        stage = _stage;
        StackPane root = new StackPane();

        WebView view = new WebView();

        WebEngine engine = view.getEngine();
        engine.load(PaymentServerRestAPI.BROWSER_URL);
        root.getChildren().add(view);
        engine.setJavaScriptEnabled(true);
        Scene scene = new Scene(root, 800, 600);
        stage.setScene(scene);

        engine.setOnResized(new EventHandler<WebEvent<Rectangle2D>>() {
            public void handle(WebEvent<Rectangle2D> ev) {
                Rectangle2D r = ev.getData();
                stage.setWidth(r.getWidth());
                stage.setHeight(r.getHeight());
            }
        });

        JSObject window = (JSObject) engine.executeScript("window");
        window.setMember("app", new BrowserApp());

        stage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }

RestClient Method: Calling to JavaFX application

// method 1 to lanch javafx
javafx.application.Application.launch(AppWebview.class);

// method 2 to lanch javafx
String[] arguments = new String[] {"123"};
AppWebview .main(arguments);
Conventionality answered 20/6, 2014 at 4:33 Comment(0)
C
29

You can't call launch() on a JavaFX application more than once, it's not allowed.

From the javadoc:

It must not be called more than once or an exception will be thrown.

Suggestion for showing a window periodically

  1. Just call Application.launch() once.
  2. Keep the JavaFX runtime running in the background using Platform.setImplicitExit(false), so that JavaFX does not shutdown automatically when you hide the last application window.
  3. The next time you need another window, wrap the window show() call in Platform.runLater(), so that the call gets executed on the JavaFX application thread.

For a short summary implementation of this approach:

If you are mixing Swing you can use a JFXPanel instead of an Application, but the usage pattern will be similar to that outlined above.

Wumpus Sample

This example is bit more complicated than it needs to be because it also involves timer tasks. However it does provide a complete stand-alone example, which might help sometimes.

import javafx.animation.PauseTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.*;

// hunt the Wumpus....
public class Wumpus extends Application {
    private static final Insets SAFETY_ZONE = new Insets(10);
    private Label cowerInFear = new Label();
    private Stage mainStage;

    @Override
    public void start(final Stage stage) {
        // wumpus rulez
        mainStage = stage;
        mainStage.setAlwaysOnTop(true);

        // the wumpus doesn't leave when the last stage is hidden.
        Platform.setImplicitExit(false);

        // the savage Wumpus will attack
        // in the background when we least expect
        // (at regular intervals ;-).
        Timer timer = new Timer();
        timer.schedule(new WumpusAttack(), 0, 5_000);

        // every time we cower in fear
        // from the last savage attack
        // the wumpus will hide two seconds later.
        cowerInFear.setPadding(SAFETY_ZONE);
        cowerInFear.textProperty().addListener((observable, oldValue, newValue) -> {
            PauseTransition pause = new PauseTransition(
                    Duration.seconds(2)
            );
            pause.setOnFinished(event -> stage.hide());
            pause.play();
        });

        // when we just can't take it  anymore,
        // a simple click will quiet the Wumpus,
        // but you have to be quick...
        cowerInFear.setOnMouseClicked(event -> {
            timer.cancel();
            Platform.exit();
        });

        stage.setScene(new Scene(cowerInFear));
    }

    // it's so scary...
    public class WumpusAttack extends TimerTask {
        private String[] attacks = {
                "hugs you",
                "reads you a bedtime story",
                "sings you a lullaby",
                "puts you to sleep"
        };

        // the restaurant at the end of the universe.
        private Random random = new Random(42);

        @Override
        public void run() {
            // use runlater when we mess with the scene graph,
            // so we don't cross the streams, as that would be bad.
            Platform.runLater(() -> {
                cowerInFear.setText("The Wumpus " + nextAttack() + "!");
                mainStage.sizeToScene();
                mainStage.show();
            });
        }

        private String nextAttack() {
            return attacks[random.nextInt(attacks.length)];
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Update, Jan 2020

Java 9 added a new feature called Platform.startup(), which you can use to trigger startup of the JavaFX runtime without defining a class derived from Application and calling launch() on it. Platform.startup() has similar restrictions to the launch() method (you cannot call Platform.startup() more than once), so the elements of how it can be applied is similar to the launch() discussion and Wumpus example in this answer.

For a demonstration on how Platform.startup() can be used, see Fabian's answer to How to achieve JavaFX and non-JavaFX interaction?

Carma answered 20/6, 2014 at 5:33 Comment(5)
@Carma can u give sample code this, for request process comleted i want close window. i have intregrated this to my spring mvc project. please can u give me sample code.Conventionality
@Carma please can u send me sample code for this problem.thanksConventionality
@Carma thank you evrey much for posting answer. but this is not valid answer for me.. i have implemented spring mvc application and hosted in my server. when server start i want to start java fx application also. and one of my spring module will call java fx application passing url, then java fx i need show that web page in webview and after processing that page i need to send back webpage output to spring mvc mobule until getting output form webpage spring will waiting then ,i need to do javafx functinality using only one thread .Conventionality
my spring application want full access contol of javafx application at any pointer of time one agian thanksConventionality
The Wumpus example is both helpful and hilarious. Thanks!Moulin
P
5

try this, I tried this and found successful

@Override
public void start() {
    super.start();
    try {
                    // Because we need to init the JavaFX toolkit - which usually Application.launch does
                    // I'm not sure if this way of launching has any effect on anything
        new JFXPanel();

        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                // Your class that extends Application
                new ArtisanArmourerInterface().start(new Stage());
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Pimply answered 13/3, 2017 at 13:11 Comment(9)
Thank you. In my scenario I solved it using Platform.setImplicitExit(false) + Application.launch(ApplicationX.class) to launch the first Application + your Platform.runLater for applications that I use later. This way I didn't need to use the new JFXPanel();Walls
Sorry, but in which class does this code go? In AppWebview?Sore
Source: powerbot.org/community/topic/…Pericardium
@Walls Hi, What if you have to pass input parameters every time in this case ? Any Idea ?Ehrsam
@Ehrsam do you mean parameters to Application.launch(myClass)? Maybe you could use some static method previously like MyClass.staticMethodToInit(value1, value2).Walls
@Walls Yes, i have to pass arguments while launching. I have posted another question over here. I am try to call it like this. Can you please advise ?#61321438Ehrsam
@Ehrsam I am not sure I understand what does this have to do with your problem. You can still pass arguments to launch method as you do.Walls
@Walls Thanks for the update. Actually, I am using JavaFx WebView as a headless browser to render the html. So, I need to be able to launch the JavaFx application multiple times by passing dynamic arguments. When i saw your comment "Platform.setImplicitExit(false) + Application.launch(ApplicationX.class) to launch the first Application + your Platform.runLater" saying you could launch it multiple times , i wanted to know more details about it.Ehrsam
@Ehrsam I've just posted an answer with something similar to what I use to launch Application multiple times. I think it isn't useful for your case, as I cannot pass arguments in Platform.runLatterWalls
W
5

I use something like this, similar to other answers.

private static volatile boolean javaFxLaunched = false;

public static void myLaunch(Class<? extends Application> applicationClass) {
    if (!javaFxLaunched) { // First time
        Platform.setImplicitExit(false);
        new Thread(()->Application.launch(applicationClass)).start();
        javaFxLaunched = true;
    } else { // Next times
        Platform.runLater(()->{
            try {
                Application application = applicationClass.newInstance();
                Stage primaryStage = new Stage();
                application.start(primaryStage);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
Walls answered 13/5, 2020 at 9:50 Comment(4)
Thank you so much Sergio. I will have a look at it. May i know how did you pass arguments every time you call myLaunch method ?Ehrsam
I don't need to pass arguments. You can use Application.launch(applicationClass, args) instead of Application.launch(applicationClass), but I think you cannot pass arguments in Platfor.runLaterWalls
Thank you for the update ! Do we have to call Platform.exit() explicitly in the Application to stop it ?Ehrsam
Thank you indeed! This example is straightforward and minimalistic.Tern

© 2022 - 2024 — McMap. All rights reserved.