Tôi đã đăng giải pháp đơn giản để xử lý tùy chỉnh các sự cố Android cách đây rất lâu. Nó hơi hacky nhưng nó hoạt động trên tất cả các phiên bản Android (bao gồm cả Lollipop).
Đầu tiên là một chút lý thuyết. Các vấn đề chính khi bạn sử dụng trình xử lý ngoại lệ không cần thiết trong Android là các ngoại lệ được đưa vào chuỗi chính (hay còn gọi là giao diện người dùng). Và đây là lý do tại sao. Khi ứng dụng bắt đầu hệ thống gọi phương thức ActivityThread.main chuẩn bị và khởi động Vòng lặp chính của ứng dụng của bạn:
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Main looper chịu trách nhiệm xử lý các thông báo được đăng trong chuỗi giao diện người dùng (bao gồm tất cả các thông báo liên quan đến hiển thị và tương tác với giao diện người dùng). Nếu một ngoại lệ được đưa ra trong chuỗi giao diện người dùng, nó sẽ bị trình xử lý ngoại lệ của bạn bắt, nhưng vì bạn không sử dụng loop()
phương pháp, bạn sẽ không thể hiển thị bất kỳ hộp thoại hoặc hoạt động nào cho người dùng vì không còn ai để xử lý thông báo giao diện người dùng cho bạn.
Giải pháp được đề xuất khá đơn giản. Chúng tôi chạy Looper.loop
phương pháp của riêng mình và bao quanh nó bằng khối try-catch. Khi một ngoại lệ được phát hiện, chúng tôi xử lý nó theo ý muốn (ví dụ: bắt đầu hoạt động báo cáo tùy chỉnh của chúng tôi) và gọi Looper.loop
lại phương thức.
Phương pháp sau thể hiện kỹ thuật này (nó nên được gọi từ Application.onCreate
người nghe):
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);
}
}
}
Như bạn có thể thấy, trình xử lý ngoại lệ chưa được sử dụng chỉ được sử dụng cho các ngoại lệ được đưa vào các luồng nền. Trình xử lý sau nắm bắt những ngoại lệ đó và truyền chúng tới chuỗi giao diện người dùng:
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);
}
});
}
}
Một dự án mẫu sử dụng kỹ thuật này có sẵn trên repo GitHub của tôi: https://github.com/idolon-github/android-crash-catcher