एंड्रॉइड में वैश्विक अनकैप्ड अपवाद हैंडलर सेट करने का आदर्श तरीका


88

मैं अपने एंड्रॉइड एप्लिकेशन में सभी थ्रेड्स के लिए एक वैश्विक अनकैप्ड अपवाद हैंडलर सेट करना चाहता हूं। इसलिए, मेरे Applicationउपवर्ग में मैंने Thread.UncaughtExceptionHandlerबिना किसी अपवाद के डिफ़ॉल्ट हैंडलर के कार्यान्वयन को निर्धारित किया ।

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

मेरे कार्यान्वयन में, मैं एक AlertDialogउपयुक्त उपयुक्त संदेश प्रदर्शित करने की कोशिश कर रहा हूं ।

हालाँकि, यह काम नहीं करता है। जब भी, किसी भी थ्रेड के लिए एक अपवाद फेंका जाता है, जो बिना संभाले चला जाता है, मुझे स्टॉक मिलता है, ओएस-डिफॉल्ट डायलॉग ("क्षमा करें!

बिना किसी अपवाद के एक डिफ़ॉल्ट हैंडलर सेट करने का सही और आदर्श तरीका क्या है?


1
क्या आप कृपया समान के लिए कोड साझा कर सकते हैं ...
Code_Life

2
यदि आप अपने अपवादों को लॉग इन करना चाहते हैं, तो acra.ch पर एक नज़र डालें । ACRA आपको Google-Doc पर या ई-मेल के माध्यम से त्रुटि-रिपोर्ट भेजने की अनुमति देता है।
अलेक्जेंडर पाचा

1
@Alexander या आप केवल Android के लिए Google Analytics का उपयोग कर सकते हैं, और सभी अपवादों को लॉग इन कर सकते हैं ...
IgGanapolsky

यह मदद कर सकता है stackoverflow.com/questions/19897628/…
Aristo Michael

जवाबों:


24

आपको बस इतना करना चाहिए। (यह सुनिश्चित करें कि आप इस प्रक्रिया को बाद में रोक सकते हैं - चीजें अनिश्चित स्थिति में हो सकती हैं।)

जांच करने वाली पहली बात यह है कि क्या एंड्रॉइड हैंडलर अभी भी कहा जा रहा है। यह संभव है कि आपके संस्करण को बुलाया जा रहा है, लेकिन यह विफल हो रहा है और जब सिस्टम प्रक्रिया को देखता है तो system_server एक सामान्य संवाद दिखा रहा है।

यह देखने के लिए कि क्या हो रहा है, अपने हैंडलर के शीर्ष पर कुछ लॉग संदेश जोड़ें। GetDefaultUncaughtExceptionHandler से परिणाम प्रिंट करें और फिर दुर्घटना का कारण बनने के लिए एक अनकहा अपवाद छोड़ दें। लॉगकैट आउटपुट पर नजर रखें कि क्या चल रहा है।


10
"त्रुटि को हैंडल करने के बाद क्रैश का कारण बनने के लिए एक बिना अपवाद के फेंकना" अभी भी महत्वपूर्ण है। मैंने अभी इसका अनुभव किया है। मेरे द्वारा अपवाद को हैंडल करने के बाद मेरा ऐप लॉक हो गया और उसने कोई अपवाद नहीं छोड़ा।
वनवर्ल्ड

@OneWorld Jepp यहाँ एक ही है - कम से कम लॉकिंग भाग के लिए - ऐसा लगता है कि ऐप को सभी के बाद दुर्घटनाग्रस्त होने से बचाने का कोई तरीका नहीं है।
AgentKnopf

@Zainodis मैंने क्रिटिसिज्म की एक कड़ी देते हुए इस सवाल का एक हल्का-सा विषय-उत्तर पोस्ट किया - मुझे लगता है कि उनके पास एक ऐसी सुविधा है जो आपको ऐप को सभी के बाद दुर्घटनाग्रस्त होने से बचाने की अनुमति देती है। निश्चित नहीं है - मैं केवल नि: शुल्क संस्करण एटीएम का उपयोग कर रहा हूं।
रिचर्ड ले मेसियर

@RichardLeMesurier संकेत के लिए धन्यवाद - मैं इसे देखूंगा :)!
AgentKnopf

अजीब!!! अगर मैं अपनी संवेदनशीलता में अपवाद को संभालता हूं तो भी मुझे नहीं बुलाया जाता है। कोई उपाय।
हिरेन दबी

12

मैंने बहुत पहले एंड्रॉइड क्रैश के कस्टम हैंडलिंग के लिए सरल समाधान पोस्ट किया था। यह थोड़ा सा हैक है लेकिन यह सभी एंड्रॉइड वर्जन (लॉलीपॉप सहित) पर काम करता है।

पहले थोड़ा सिद्धांत। जब आप एंड्रॉइड में अनकैप्ड अपवाद हैंडलर का उपयोग करते हैं तो मुख्य मुद्दे मुख्य (उर्फ यूआई) थ्रेड में अपवाद के साथ आते हैं। और यहाँ क्यों है। जब ऐप शुरू होता है तो सिस्टम कॉल करता है 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();

    // the following handler is used to catch exceptions thrown in background threads
    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


जैसा कि कोई अनुमान लगा सकता है, इस तरह से न केवल कस्टम त्रुटि संवाद दिखाना संभव है, बल्कि उपयोगकर्ता को अपवाद को अनदेखा करने और एप्लिकेशन के साथ काम जारी रखने की अनुमति देने के लिए (और जब यह प्रकाशित एप्लिकेशन के लिए एक बुरा विचार जैसा दिखता है, तो यह हो सकता है) डिबग या परीक्षण सत्र के दौरान बहुत सुविधाजनक है)।
आइडलोन

नमस्ते, जबकि यह बिना किसी अपवाद के पकड़ने में काम करता है, लेकिन किसी कारण से, यह कोड हमेशा अपवादों को फेंक रहा है। प्रारंभ में मैं हालांकि यह रनटाइम एक्सेप्शन लाइन के कारण था जो आपके पास स्टार्टचैकर पद्धति में है, लेकिन मुझे इसे हटाने के बाद भी अपवाद मिल रहा है। मुझे यकीन नहीं है कि अगर यह एक आवश्यक चीज है। वैसे भी मुझे जो अपवाद मिलता है, वह है java.lang.RuntimeException: Performing pause of activity that is not resumed। मेरा मानना ​​है कि जब मैं अपने स्वयं के लूपर को शुरू करने की कोशिश कर रहा हूं तो सिस्टम उस गतिविधि को रोक देता है जो शुरू होने वाली है? मुझे यकीन नहीं है लेकिन किसी भी मदद की सराहना की जाएगी। धन्यवाद
sttaq

यह भी कि अगर मैं स्टार्टचैकर को हटा देता हूं यानी आपके कोड के बिना ऐप चलाता हूं तो बिना किसी अपवाद के सब कुछ ठीक चलता है।
sttaq

@sttaq आप Android के किस संस्करण का उपयोग करते हैं?
आइडलोन

मुझे लगता है कि मैं 2.3.x पर यह कोशिश कर रहा था
sttaq

3

मुझे लगता है कि निष्क्रिय करने के लिए लगता है कि आपकी पहुंच से बाहर () विधि पिछलेहांडलर को कॉल न करें ।uncaughtException () जहां पिछलेहैंडलर द्वारा सेट किया गया है

previousHandler = Thread.getDefaultUncaughtExceptionHandler();

2

FWIW मुझे पता है कि यह थोड़ा ऑफ-टॉपिक है, लेकिन हम Crittercism के मुफ्त प्लान का उपयोग कर रहे हैं सफलता के साथ रहे हैं। वे कुछ प्रीमियम सुविधाएँ भी प्रदान करते हैं, जैसे अपवाद को संभालना ताकि ऐप क्रैश न हो।

नि: शुल्क संस्करण में, उपयोगकर्ता अभी भी दुर्घटना देखता है, लेकिन कम से कम मुझे ईमेल और स्टैक ट्रेस मिलता है।

हम iOS संस्करण का भी उपयोग करते हैं (लेकिन मैंने अपने सहयोगियों से सुना है कि यह उतना अच्छा नहीं है)।


यहाँ समान प्रश्न हैं:


1

जब तक आप कॉल नहीं करते तब तक यह काम नहीं करता है

android.os.Process.killProcess(android.os.Process.myPid());

अपने UncaughtExceptionHandler के बहुत अंत में।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.