ฉันโพสต์วิธีง่ายๆสำหรับการจัดการข้อขัดข้องของ Android แบบกำหนดเองเมื่อนานมาแล้ว มันแฮ็คเล็กน้อย แต่ใช้ได้กับ Android ทุกรุ่น (รวมถึง Lollipop)
ก่อนอื่นทฤษฎีเล็กน้อย ปัญหาหลักเมื่อคุณใช้ตัวจัดการข้อยกเว้นที่ไม่ถูกจับใน Android มาพร้อมกับข้อยกเว้นในเธรดหลัก (aka 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
วิธีการของเราเองและล้อมรอบด้วยบล็อกลองจับ เมื่อพบข้อยกเว้นเราจะดำเนินการตามที่เราต้องการ (เช่นเริ่มกิจกรรมรายงานที่กำหนดเอง) และ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);
}
});
}
}
โครงการตัวอย่างที่ใช้เทคนิคนี้มีอยู่ใน repo GitHub ของฉัน: https://github.com/idolon-github/android-crash-catcher