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