Is there a chance to get -splash: work for

2019-07-18 13:59发布

问题:

I am launching my Scala SWT application using:

java -splash:splash.jpg -jar application.jar

Using JDK 1.6.0 on Mac OS X 10.9.1 the splash screen was opened immediately (seconds before the actual application window opened).

I used the following code to close the splash screen when the SWT application window opened:

// When the window opens for the first time close the splash screen if exists
val splash = SplashScreen.getSplashScreen
if (splash != null) {
  shell.addShellListener(new ShellAdapter {
    override def shellActivated(event: ShellEvent) {
      shell.removeShellListener(this)
      splash.close
    }
  })
}

The behavior was as intended: I got a very early splash screen that was closed when the application was ready.

Now on JDK 1.7.0_45 the splash screen is opened the moment the application window was opened and the application freezes at splash.close.

I read https://www.java.net//node/668622 that some changes were made to the SplashScreen API from Java 6 to Java 7 but that doesn't explain the totally different behavior.

Is there a change getting the JVM splash screen run on Java 7 for a SWT application?

FYI: I am using plain SWT without Eclipse (that includes the Eclipse launcher that supports splash screens) around it.

回答1:

Maybe there will be a solution for this in JDK9 or later. At the moment with JDK8 on OS X Yosemite there is no improvement on this problem.

At the moment I'll use code from this snippet here or this one there. Both of them are working.

Hopefully the bug will be closed in JDK9!



回答2:

Finally found the answer! Because the splash is also created on the first thread we need to do some message handling, which can be achived by having an SWT event loop running on the main thread.

While this is running you can interact with the Splash screen without freezing from other threads in the application.

I wrapped all calls to the SplashScreen handling stuff (also the rendering on it and dismissing it) in Runnables that are passed to this function:

private static void executeSafeForMac( Runnable r ) {
    // On non Mac systems no problem
    if( System.getProperty("os.name").toLowerCase().indexOf("mac")<0 ) {
        r.run();
        return;
    }

    // On Mac we must be moar intelligent
    Display display = Display.getDefault();
    final Semaphore sem = new Semaphore(0);
    Thread t = new Thread( ()->{
        r.run();
        sem.release(); // Can be anything.
        display.asyncExec(()->{}); // Ensure the Event loop has one last thing to do
    }, "SplashScreenInteractor" );
    t.start();

    // Okay, we do SWT event loop stuff to make the SplashScreen responsible until the  
    // SplashScreen stuff doing Runnable has been done and the semaphore is released.
    while( !display.isDisposed() && !sem.tryAcquire() ) {
        if( !display.readAndDispatch() ) {
            display.sleep();
        }
    }

}