2016-03-12 6 views
0

В моем приложении JavaFX я хочу показать диалоговое окно с ошибкой и выйти из приложения, когда возникает какое-то неожиданное исключение. Так что в моем главном-методе я настроил неперехваченный обработчик исключений по умолчанию перед запуском приложения:JavaFX: Как показать диалоговое окно с ошибкой при запуске метода start?

setDefaultUncaughtExceptionHandler((thread, cause) -> { 
    try { 
     cause.printStackTrace(); 
     final Runnable showDialog =() -> { 
      // create dialog and show 
     }; 
     if (Platform.isFxApplicationThread()) { 
      showDialog.run(); 
     } else { 
      runAndWait(showDialog); 
     } 
    } catch (Throwable t) { 
     // ??? 
    } finally { 
     System.exit(-1); 
    } 
}); 

launch(MyApp.class); 

Пояснения: Когда неперехваченное обработчик исключений выполняются на тему JavaFX Application (FXAT), я просто запустить код для отображения диалога. Это, конечно, не работает, когда обработчик исключений не вызывается FXAT. В этом случае я должен нажать код на FXAT. Но я не могу использовать Platform.runLater, потому что тогда мое приложение выйдет до появления диалогового окна. Итак, я сделал этот настраиваемый метод runAndWait, который внутренне выталкивает runnable через Platform.runLater, но ждет выполнения исполняемого файла (с некоторым механизмом задержек обратного отсчета).

Теперь проблема с этим: когда в моем методе start() возникает исключение, мое приложение застревает. Поскольку он пытается подождать, пока не покажет выполнение диалогового окна, но FXAT никогда не выполняет это выполнение. Я думаю, это потому, что, когда метод start() выходит из строя с исключением, FXAT просто мертв? Я не уверен, является ли это особым случаем для метода start(), или это произойдет в любой ситуации, когда исключение выбрано и не попадает в код, который выполняется FXAT.

В Swing, как я знаю, EDT представляет собой сложную архитектуру, состоящую из нескольких потоков. Дело не в том, что когда какое-то исполнение на EDT потерпело неудачу, весь Swing сломался. Но вот что, похоже, происходит?

Так что я могу здесь сделать? Как я могу показать пользователю, что приложение не может запустить?

+0

«Я не могу использовать' Platform.runLater() ', потому что тогда мое приложение завершит работу до появления диалогового окна». Вызывает ли это 'Platform.setImplicitExit (false);' исправляет это? –

+0

нет конечно нет. причиной выхода приложения является вызов System.exit() в моем обработчике исключений. – user3237736

+0

Подожди, я идиот. забудьте эту точку, когда программа выходит слишком рано. потому что я мог просто переместить вызов System.exit в Runnable для потока FX. Тем не менее, основная проблема заключается в том, что я не могу ничего запускать в потоке FX, когда метод start генерирует исключение. – user3237736

ответ

1

Ну ....

У меня есть решение, но я не особенно рекомендую. По умолчанию Application.launch() поймает исключение, созданное методом start, выйдет из платформы FX, а затем восстановит исключение. Поскольку поток приложений FX отключился, когда выполняется обработчик невыполненных исключений по умолчанию, ожидая, что что-то произойдет в потоке приложения FX, просто блокируется бесконечно.

Исключением является то, что приложение FX работает в веб-запуске. Способ проверки пусковой установки заключается в проверке наличия диспетчера безопасности. Поэтому (действительно, очень уродливое) решение об установке заключается в установке диспетчера безопасности, чтобы он выглядел так, как будто вы работаете в режиме веб-запуска. Эта линия будет установить разрешительный менеджер безопасности:

System.setSecurityManager(new SecurityManager(){ 
    @Override 
    public void checkPermission(Permission perm) {} 
}); 

Вот SSCCE:

import java.lang.Thread.UncaughtExceptionHandler; 
import java.security.Permission; 
import java.util.concurrent.FutureTask; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.scene.control.Alert; 
import javafx.scene.control.Alert.AlertType; 

public class ShowDialogOnException { 

    public static final UncaughtExceptionHandler ALERT_EXCEPTION_HANDLER = (thread, cause) -> { 
     try { 
      cause.printStackTrace(); 
      final Runnable showDialog =() -> { 
       Alert alert = new Alert(AlertType.ERROR); 
       alert.setContentText("An unknown error occurred"); 
       alert.showAndWait(); 
      }; 
      if (Platform.isFxApplicationThread()) { 
       showDialog.run(); 
      } else { 
       FutureTask<Void> showDialogTask = new FutureTask<Void>(showDialog, null); 
       Platform.runLater(showDialogTask); 
       showDialogTask.get(); 
      } 
     } catch (Throwable t) { 
      t.printStackTrace(); 
     } finally { 
      System.exit(-1); 
     } 
    }; 



    public static void main(String[] args) { 
     System.setSecurityManager(new SecurityManager(){ 
      @Override 
      public void checkPermission(Permission perm) {} 
     }); 
     Thread.setDefaultUncaughtExceptionHandler(ALERT_EXCEPTION_HANDLER); 
     Application.launch(App.class, args); 
    } 
} 

и тест приложение:

import javafx.application.Application; 
import javafx.stage.Stage; 

public class App extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
     throw new Exception("An exception"); 
    } 

    @Override 
    public void stop() { 
     System.out.println("Stop"); 
    } 

} 

Как я уже сказал, это действительно что-то большой взломать, и я действительно не рекомендую это, если у вас нет другого выбора.

+0

Спасибо за этот ответ! Однако я согласен с вами в том, что это довольно неприятное обходное решение. Я думаю, лучшее решение для меня состояло бы в том, чтобы убедиться, что у меня нет неустойчивого кода в моем методе запуска, и ограничить его логикой, а затем запустить другой материал в новом потоке прямо перед показом сцены. – user3237736

+0

Редактирование: или на самом деле, даже лучше, я просто поместил весь код из метода start в блок try-catch и покажу диалоговое окно с ошибкой и выхожу прямо из приложения. Остается только вопрос, который сохраняется, если такой вид отключения FX происходит и в других местах, чем только метод запуска, например. когда некоторая обработка событий завершается с исключением ?! но я проверю это, я думаю, это будет не то же самое. – user3237736

+0

Да, я имел в виду добавить либо в комментарии, либо в ответ, что фундаментальное отличие здесь от Swing заключается в том, что метод 'start()' действительно является неотъемлемой частью запуска инструментария, поэтому в некотором смысле отказ в начале метод является фатальным для всего пользовательского интерфейса. Минимизация кода в 'start()' и факторинг всего остального в другом месте - хорошая практика по ряду причин. После того, как метод запуска завершен, нет проблемы, поэтому, например, он отлично работает, если в обработчике событий происходит неперехваченное исключение и т. Д. –

 Смежные вопросы

  • Нет связанных вопросов^_^