90

Androidアプリケーションのすべてのスレッドにグローバルなキャッチされない例外ハンドラーを設定したいと思います。そのため、私のApplicationサブクラスではThread.UncaughtExceptionHandler、キャッチされない例外のデフォルトハンドラーとしての実装を設定しました。

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

私の実装では、AlertDialog適切な例外メッセージを表示しようとしています。

ただし、これは機能していないようです。処理されないスレッドに対して例外がスローされるたびに、標準のOSデフォルトダイアログ(「申し訳ありません!-アプリケーションが停止しました-予期せずダイアログ」)が表示されます。

キャッチされない例外のデフォルトハンドラーを設定するための正しく理想的な方法は何ですか?

4

5 に答える 5

24

それはあなたがする必要があるすべてであるはずです。(後でプロセスを停止させるようにしてください。状況が不確実になる可能性があります。)

最初に確認するのは、Androidハンドラーがまだ呼び出されているかどうかです。バージョンが呼び出されているが致命的に失敗し、system_serverがプロセスのクラッシュを検出したときに一般的なダイアログを表示している可能性があります。

ハンドラーの上部にいくつかのログメッセージを追加して、そこに到達しているかどうかを確認します。getDefaultUncaughtExceptionHandlerからの結果を出力してから、キャッチされなかった例外をスローしてクラッシュを引き起こします。logcatの出力を監視して、何が起こっているかを確認してください。

于 2010-05-04T21:04:58.920 に答える
14

私はずっと前にAndroidクラッシュのカスタム処理のための簡単な解決策を投稿しました。少しハッキーですが、すべてのAndroidバージョン(Lollipopを含む)で動作します。

最初に少し理論を説明します。Androidでキャッチされない例外ハンドラーを使用する場合の主な問題は、メイン(別名UI)スレッドでスローされる例外にあります。そしてここに理由があります。アプリが起動すると、システムはActivityThread.mainメソッドを呼び出します。このメソッドは、アプリのメインルーパーを準備して起動します。

public static void main(String[] args) {
  …
  …
    Looper.prepareMainLooper();
  …
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

メインルーパーは、UIスレッドに投稿されたメッセージ(UIのレンダリングとインタラクションに関連するすべてのメッセージを含む)の処理を担当します。UIスレッドで例外がスローされると、例外ハンドラーによってキャッチされますが、loop()メソッドがないため、UIメッセージを処理する人がいないため、ユーザーにダイアログやアクティビティを表示することはできません。あなたのために。

提案されたソリューションは非常に単純です。メソッドを独自に実行Looper.loopし、try-catchブロックで囲みます。例外がキャッチされると、必要に応じて処理し(たとえば、カスタムレポートアクティビティを開始します)、Looper.loopメソッドを再度呼び出します。

次のメソッドは、この手法を示しています(Application.onCreateリスナーから呼び出す必要があります)。

private void startCatcher() {
    UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();

    // the following handler is used to catch exceptions thrown in background threads
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler()));

    while (true) {
        try {
            Looper.loop();
            Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler);
            throw new RuntimeException("Main thread loop unexpectedly exited");
        } catch (Throwable e) {
            showCrashDisplayActivity(e);
        }
    }
}

ご覧のとおり、キャッチされなかった例外ハンドラーは、バックグラウンドスレッドでスローされた例外にのみ使用されます。次のハンドラーは、これらの例外をキャッチし、UIスレッドに伝播します。

static class UncaughtHandler implements UncaughtExceptionHandler {

    private final Handler mHandler;

    UncaughtHandler(Handler handler) {
        mHandler = handler;
    }

    public void uncaughtException(Thread thread, final Throwable e) {
        mHandler.post(new Runnable() {
            public void run() {
                throw new BackgroundException(e);
            }
        });
    }
}

この手法を使用するプロジェクトの例は、私のGitHubリポジトリで入手できます:https ://github.com/idolon-github/android-crash-catcher

于 2015-01-24T14:25:07.603 に答える
3

uncaughtException()メソッドでpreviousHandlerが設定されているpreviousHandler.uncaughtException()を呼び出さないようにすることを無効にすると思います。

previousHandler = Thread.getDefaultUncaughtExceptionHandler();
于 2010-05-04T15:11:47.047 に答える
2

FWIWこれは少し話題から外れていることは知っていますが、Crittercismの無料プランを使用して成功を収めています。また、アプリがクラッシュしないように例外を処理するなど、いくつかのプレミアム機能も提供します。

無料版では、ユーザーにはまだクラッシュが表示されますが、少なくとも私は電子メールとスタックトレースを取得します。

iOSバージョンも使用しています(ただし、同僚からはそれほど良くないと聞いています)。


同様の質問があります:

于 2012-08-28T06:43:46.753 に答える
2

電話するまで機能しません

android.os.Process.killProcess(android.os.Process.myPid());

UncaughtExceptionHandlerの最後にあります。

于 2014-02-26T08:53:17.643 に答える