Saya memposting solusi sederhana untuk penanganan khusus Android crash sejak lama. Ini sedikit hacky namun bekerja pada semua versi Android (termasuk Lollipop).
Pertama, sedikit teori. Masalah utama saat Anda menggunakan pengendali pengecualian tidak tertangkap di Android datang dengan pengecualian yang dilemparkan di utas utama (alias UI). Dan inilah alasannya. Saat aplikasi memulai sistem memanggil metode ActivityThread.main yang mempersiapkan dan memulai looper utama aplikasi Anda:
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper utama bertanggung jawab untuk memproses pesan yang diposting di thread UI (termasuk semua pesan yang terkait dengan rendering dan interaksi UI). Jika pengecualian dilempar di thread UI, itu akan ditangkap oleh penangan pengecualian Anda, tetapi karena Anda keluar dari loop()
metode, Anda tidak akan dapat menampilkan dialog atau aktivitas apa pun kepada pengguna karena tidak ada yang tersisa untuk memproses pesan UI untukmu.
Solusi yang diusulkan cukup sederhana. Kami menjalankan Looper.loop
metode sendiri dan mengelilinginya dengan blok coba-tangkap. Saat pengecualian tertangkap, kami memprosesnya sesuai keinginan (misalnya memulai aktivitas laporan kustom kami) dan memanggil Looper.loop
metode lagi.
Metode berikut mendemonstrasikan teknik ini (harus dipanggil dari Application.onCreate
pendengar):
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);
}
}
}
Seperti yang Anda lihat, penangan pengecualian tak tertangkap hanya digunakan untuk pengecualian yang dilemparkan di utas latar belakang. Penangan berikut menangkap pengecualian tersebut dan menyebarkannya ke UI thread:
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);
}
});
}
}
Contoh proyek yang menggunakan teknik ini tersedia di repo GitHub saya: https://github.com/idolon-github/android-crash-catcher