Androidでグローバルな未猛ート例外ハンドラーを設定する理想的な方法
-
02-10-2019 - |
質問
Androidアプリケーションのすべてのスレッドに対して、グローバルな猛攻撃例外ハンドラーを設定したいと思います。だから、私の中で Application
サブクラス私はの実装を設定しました Thread.UncaughtExceptionHandler
猛攻撃の例外のデフォルトハンドラーとして。
Thread.setDefaultUncaughtExceptionHandler(
new DefaultExceptionHandler(this));
私の実装では、私は AlertDialog
適切な例外メッセージを表示します。
ただし、これは機能しないようです。ハンドルされていないスレッドの例外がスローされるたびに、OS-Defaultダイアログ(「ごめんなさい! - アプリケーションハスストップではないと考えられているダイアログ」)を取得します。
無作法な例外のためにデフォルトのハンドラーを設定する正しい理想的な方法は何ですか?
解決
それはあなたがする必要があるすべてであるべきです。 (その後、プロセスを停止させることを確認してください - 物事は不確実な状態にある可能性があります。)
最初に確認するのは、Androidハンドラーがまだ呼び出されているかどうかです。バージョンが呼び出されているが、致命的に失敗し、System_Serverがプロセスのクラッシュを見ると一般的なダイアログを表示している可能性があります。
ハンドラーの上部にログメッセージを追加して、そこに到達しているかどうかを確認します。 getDefaultunCaughtExceptionHandlerの結果を印刷してから、猛攻撃の例外をスローしてクラッシュを引き起こします。ログキャット出力に注目して、何が起こっているのかを確認してください。
他のヒント
シンプルを投稿しました 解決 Androidクラッシュのカスタム処理のためにずっと前に。少しハッキーですが、すべてのAndroidバージョン(Lollipopを含む)で動作します。
最初に少しの理論。 AndroidでUncaught Exception Handlerを使用する場合の主な問題は、メイン(別名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()
メソッドユーザーにダイアログやアクティビティをユーザーに表示することはできません。
提案されたソリューションは非常に簡単です。私たちは走る Looper.loop
私たち自身のメソッドで、トライキャッチブロックでそれを囲みます。例外がキャッチされたら、必要に応じて処理します(たとえば、カスタムレポートアクティビティを開始します)。 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);
}
}
}
ご覧のとおり、Uncaught Exception Handlerは、バックグラウンドスレッドにスローされた例外のためにのみ使用されます。次のハンドラーはこれらの例外をキャッチし、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
fwiwこれはわずかにトピックであることを知っていますが、私たちは使用しています Crittercismの無料計画 成功して。また、アプリがクラッシュしないように例外を処理するなど、いくつかのプレミアム機能も提供します。
無料版では、ユーザーは引き続きクラッシュを確認しますが、少なくともメールとスタックトレースが表示されます。
また、iOSバージョンも使用しています(しかし、同僚からそれほど良くないと聞いています)。
同様の質問があります:
uncaughtexception()メソッドでは、以前のハンドラーが設定されている場合、以前のhandler.uncaughtexception()に電話しないでください。
previousHandler = Thread.getDefaultUncaughtExceptionHandler();
電話するまで機能しません
android.os.Process.killProcess(android.os.Process.myPid());
UncaugtExceptionHandlerの最後に。