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