Androidでグローバルなキャッチされない例外ハンドラーを設定する理想的な方法


88

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

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

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

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

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


1
あなたが同じのためのコードを共有してくださいすることができます...
Code_Life

2
例外をログに記録したい場合は、acra.chをご覧ください。ACRAを使用すると、エラーレポートをGoogleドキュメントまたは電子メールで送信できます。
アレクサンダーパチャ2013年

1
@Alexanderまたは、Android向けGoogle Analyticsを使用して、必要なすべての例外をログに記録することもできます...
IgorGanapolsky 2013年

これは助けになるかもしれませんstackoverflow.com/questions/19897628/…–
Aristo Michael

回答:


24

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

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

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


10
「エラーを処理した後、キャッチされない例外をスローしてクラッシュを引き起こす」ことは依然として重要です。私はちょうどそれを経験しました。例外を処理した後、アプリがロックされ、キャッチされなかった例外がスローされませんでした。
OneWorld 2010

@OneWorld Jeppはここでも同じです-少なくともロック部分については-結局のところ、アプリがクラッシュするのを「防ぐ」方法はないようです。
AgentKnopf 2012

@Zainodis Crittercismへのリンクを提供するこの質問へのややオフトピックの回答を投稿しました-結局、アプリがクラッシュするのを「防ぐ」ことができる機能があると思います。わからない-私は無料版のATMのみを使用しています。
リチャードルメスリエ2012

@RichardLeMesurierヒントをありがとう-私はそれをチェックします:)!
AgentKnopf 2012

奇妙な!!! アクティビティで例外を処理しても、uncaughtexceptionが呼び出されます。何か案が。
Hiren Dabhi 2013年

12

私はずっと前に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年

こんにちは、これはキャッチされなかった例外をキャッチするのに役立ちますが、何らかの理由で、このコードは常に例外をスローしています。最初は、startCatcherメソッドにあるRuntimeException行が原因でしたが、削除した後も例外が発生します。それが必須かどうかはわかりません。とにかく私が得る例外はjava.lang.RuntimeException: Performing pause of activity that is not resumedです。自分のルーパーを開始しようとすると、システムが開始しようとしているアクティビティを一時停止すると思いますか?よくわかりませんが、助けていただければ幸いです。ありがとう
sttaq 2015

また、startCatcherを削除した場合、つまりコードなしでアプリを実行した場合も、例外なくすべてが正常に機能します。
sttaq 2015

@sttaqどのバージョンのAndroidを使用していますか?
アイドル2015年

私はこれを2.3.xで試していたと思います
sttaq

3

私はあなたのuncaughtException()メソッドでpreviousHandlerが設定されているpreviousHandler.uncaughtException()を呼び出さないことを無効にすると思います

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

2

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

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

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


同様の質問があります:


1

電話をかけるまで機能しません

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

UncaughtExceptionHandlerの最後にあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.