0

JavaFX アプリケーションで、予期しない例外が発生するたびにエラー ダイアログを表示してアプリを終了したいと考えています。だから私のメインメソッドでは、アプリを起動する前にデフォルトのキャッチされていない例外ハンドラーを設定しました:

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 アプリケーション スレッド (FXAT) で実行されると、ダイアログを表示するためのコードを実行するだけです。もちろん、例外ハンドラが FXAT によって呼び出されない場合、これは機能しません。この場合、コードを FXAT にプッシュする必要があります。しかしPlatform.runLater、ダイアログが表示される前にアプリが終了するため、使用できません。runAndWaitそこで、ランナブルを 経由で内部的にプッシュするカスタム メソッドを作成しましたPlatform.runLaterが、ランナブルの実行まで待機します (カウントダウン ラッチ メカニズムを使用)。

これに関する問題: start() メソッドで例外が発生すると、アプリが動かなくなります。ダイアログが表示されるまで待機しようとしますが、FXAT は決してこの実行を行いません。これは、start() メソッドが例外で失敗した場合、FXAT が死んでいるからだと思いますか? これが start() メソッドの特殊なケースなのか、それとも例外がスローされ、FXAT によって実行されるコード内でキャッチされない場合に発生するのかはわかりません。

私が知っているように、Swing では、EDT は複数のスレッドで構成される複雑なアーキテクチャです。EDT での実行の一部が失敗したときに Swing 全体が壊れたということはありませんでした。しかし、これは何が起こっているようですか?

ここで何ができますか?アプリケーションを起動できないことをユーザーに示すにはどうすればよいですか?

4

1 に答える 1

1

良い....

解決策はありますが、特にお勧めしません。デフォルトでApplication.launch()は、start メソッドによってスローされた例外をキャッチし、FX プラットフォームを終了してから、例外を再スローします。デフォルトのキャッチされていない例外ハンドラが実行されると FX アプリケーション スレッドがシャットダウンされるため、FX アプリケーション スレッドで何かが発生するのを待っていると、無期限にブロックされます。

これに対する例外は、FX アプリケーションが Web Start で実行されている場合です。ランチャーがこれを確認する方法は、セキュリティ マネージャーの存在を確認することです。したがって、(本当に、本当に醜い) 回避策は、Web 開始モードで実行しているように見えるように、セキュリティ マネージャーをインストールすることです。この行は、寛容なセキュリティ マネージャーをインストールします。

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");
    }

}

私が言ったように、これは本当に大きなハックのようなものであり、他に選択肢がない限り、これはあまりお勧めしません.

于 2016-03-12T16:21:40.130 に答える