मैंने बहुत पहले एंड्रॉइड क्रैश के कस्टम हैंडलिंग के लिए सरल समाधान पोस्ट किया था। यह थोड़ा सा हैक है लेकिन यह सभी एंड्रॉइड वर्जन (लॉलीपॉप सहित) पर काम करता है।
पहले थोड़ा सिद्धांत। जब आप एंड्रॉइड में अनकैप्ड अपवाद हैंडलर का उपयोग करते हैं तो मुख्य मुद्दे मुख्य (उर्फ यूआई) थ्रेड में अपवाद के साथ आते हैं। और यहाँ क्यों है। जब ऐप शुरू होता है तो सिस्टम कॉल करता है ActivityThread.main विधि जो आपके ऐप के मुख्य लूपर को तैयार और शुरू करती है :
public static void main(String[] args) {
…
…
Looper.prepareMainLooper();
…
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
मुख्य लूपर UI थ्रेड में पोस्ट किए गए संदेशों को संसाधित करने के लिए जिम्मेदार है (UI रेंडरिंग और इंटरैक्शन से संबंधित सभी संदेशों सहित)। अगर यूआई थ्रेड में कोई अपवाद फेंका जाता है तो यह आपके अपवाद हैंडलर द्वारा पकड़ा जाएगा, लेकिन जब से आप loop()
विधि से बाहर हैं, तो आप उपयोगकर्ता को कोई भी संवाद या गतिविधि नहीं दिखा पाएंगे क्योंकि यूआई संदेशों को संसाधित करने के लिए कोई नहीं बचा है तुम्हारे लिए।
प्रस्तावित समाधान काफी सरल है। हम 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);
}
});
}
}
एक उदाहरण परियोजना जो इस तकनीक का उपयोग करती है, मेरे GitHub repo पर उपलब्ध है: https://github.com/idolon-github/android-crash-catcher