13

Thread.setDefaultUncaughtExceptionHandler` जब मेरी Android एप्लिकेशन एक अपवाद फेंक एक संवाद दिखाएं, मैं उपयोगकर्ता को बताने के लिए एक कस्टम संवाद दिखाना चाहते हैं वहाँ कुछ गलत हुआ है, इसलिए मैं Thread.setDefaultUncaughtExceptionHandler का उपयोग एक वैश्विक अपवाद संचालक स्थापित करने के लिए:में `

public class MyApplication extends Application { 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
      @Override 
      public void uncaughtException(Thread thread, final Throwable ex) { 
       AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext()); 
       builder.setTitle("There is something wrong") 
         .setMessage("Application will exit:" + ex.toString()) 
         .setPositiveButton("OK", new DialogInterface.OnClickListener() { 

          @Override 
          public void onClick(DialogInterface dialog, int which) { 
           // throw it again 
           throw (RuntimeException) ex; 
          } 
         }) 
         .show(); 
      } 
     }); 
    } 

} 

लेकिन मैं इसे किसी भी अपवाद नहीं है पाया, AlertDialog नहीं दिखाया जाएगा, बजाय, आवेदन ब्लॉक और थोड़ी देर के बाद, यह सिस्टम संवाद दिखाएगा:

X app is not responding. Would you like to close it? 
Wait | OK 

अब मुझे क्या करना चाहिए ?


अद्यतन

लॉग:

11-16 12:54:16.017: WARN/WindowManager(90): Attempted to add window with non-application token WindowToken{b38bb6a8 token=null}. Aborting. 

ऐसा लगता है त्रुटि से new AlertDialog.Builder(getApplicationContext());

आ रहा है लेकिन इस Application उपवर्ग में अपवाद संचालक है, मैं कैसे निर्धारित कर सकते हैं इसके लिए एक गतिविधि उदाहरण?

+0

लॉकेट को भी पेस्ट करें – waqaslam

+0

यह संदेश तब दिखाई देता है जब एप्लाका टयन बहुत अधिक समय ले रहा है (उस मामले में कोई अपवाद नहीं है)। मेरी सिफारिश है कि अपने भारी कार्यों को एक AsyncTask में ले जाने का प्रयास करें। – richardtz

उत्तर

28

आप यहां से कोई यूआई ऑपरेशन नहीं कर सकते हैं। बस एक और गतिविधि/स्प्लैश स्क्रीन शुरू करें। दुर्घटना को दर्शाने और उस गतिविधि में संवाद दिखाने के लिए एक इरादा अतिरिक्त पास करें।

/* 
    * (non-Javadoc) 
    * 
    * @see 
    * java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java. 
    * lang.Thread, java.lang.Throwable) 
    */ 
    @Override 
    public void uncaughtException(Thread t, final Throwable e) { 
     StackTraceElement[] arr = e.getStackTrace(); 
     final StringBuffer report = new StringBuffer(e.toString()); 
     final String lineSeperator = "-------------------------------\n\n"; 
     report.append(DOUBLE_LINE_SEP); 
     report.append("--------- Stack trace ---------\n\n"); 
     for (int i = 0; i < arr.length; i++) { 
      report.append(" "); 
      report.append(arr[i].toString()); 
      report.append(SINGLE_LINE_SEP); 
     } 
     report.append(lineSeperator); 
     // If the exception was thrown in a background thread inside 
     // AsyncTask, then the actual exception can be found with getCause 
     report.append("--------- Cause ---------\n\n"); 
     Throwable cause = e.getCause(); 
     if (cause != null) { 
      report.append(cause.toString()); 
      report.append(DOUBLE_LINE_SEP); 
      arr = cause.getStackTrace(); 
      for (int i = 0; i < arr.length; i++) { 
       report.append(" "); 
       report.append(arr[i].toString()); 
       report.append(SINGLE_LINE_SEP); 
      } 
     } 
     // Getting the Device brand,model and sdk verion details. 
     report.append(lineSeperator); 
     report.append("--------- Device ---------\n\n"); 
     report.append("Brand: "); 
     report.append(Build.BRAND); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Device: "); 
     report.append(Build.DEVICE); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Model: "); 
     report.append(Build.MODEL); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Id: "); 
     report.append(Build.ID); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Product: "); 
     report.append(Build.PRODUCT); 
     report.append(SINGLE_LINE_SEP); 
     report.append(lineSeperator); 
     report.append("--------- Firmware ---------\n\n"); 
     report.append("SDK: "); 
     report.append(Build.VERSION.SDK); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Release: "); 
     report.append(Build.VERSION.RELEASE); 
     report.append(SINGLE_LINE_SEP); 
     report.append("Incremental: "); 
     report.append(Build.VERSION.INCREMENTAL); 
     report.append(SINGLE_LINE_SEP); 
     report.append(lineSeperator); 

     Log.e("Report ::", report.toString()); 
     Intent crashedIntent = new Intent(BaseActivity.this, SplashActivity.class); 
     crashedIntent.putExtra(EXTRA_CRASHED_FLAG, "Unexpected Error occurred."); 
     crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 
     crashedIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     startActivity(crashedIntent); 

     System.exit(0); 
     // If you don't kill the VM here the app goes into limbo 

    } 

यह भी देखें:

Android UncaughtExceptionHandler that instantiates an AlertDialog breaks

Toast not showing up in UnCaughtExceptionHandler

How to start activity from UncaughtExceptionHandler if this is main thread crashed?

मैं यह कैसे करते:

मेरे पास बेसएक्टिविटी है जो गतिविधि को बढ़ाती है, और गतिविधि के निर्माण में मैंने UncaughtExceptionHandler सेट किया है। मेरी सभी गतिविधियां गतिविधि की बजाय बेसएक्टिविटी का विस्तार करती हैं।

कुंजी

  1. आप Application.onCreate में अपवाद संचालक निर्धारित नहीं कर सकते, बजाय, आप एक BaseActivity बना सकते हैं और इसके बारे में onCreate पद्धति पर यह स्थापित करना चाहिए।
  2. SplashActivity शुरू करने के बाद, हम बुलाना चाहिए System.exit(0)
  3. हम त्रुटि उदाहरण को रोक नहीं सकते SplashActivity को साझा करने के लिए है, क्योंकि यह नष्ट हो जाएगा, इसके बजाय, हम कुछ त्रुटि संदेश देना या यह फाइल में बच सकते हैं।
+0

आप एप्लिकेशन में अपवाद हैंडलर क्यों सेट नहीं कर सकते हैं। कॉरेट? इसे देखें: http://www.intertech.com/Blog/android-handling-the-unexpected/ – Rotem

+0

'System.exit (1)' (या कोई गैर-शून्य मान) बेहतर होगा क्योंकि यह असामान्य निकास का संकेत देगा। – infranoise

+0

@ जावा एप्लिकेशन परिप्रेक्ष्य से एंड्रॉनोनोइस एंड्रॉइड परिप्रेक्ष्य से हां इसका कोई प्रभाव नहीं पड़ता है। आपको उस डिवाइस तक पहुंच भी नहीं होगी जहां यह ज्यादातर बार दुर्घटनाग्रस्त हो जाती है। – Atrix1987

4

ऐसा लगता है कि प्रदान किया गया समाधान काम नहीं करता है (कम से कम एंड्रॉइड 4.0 और उसके बाद के संस्करण के लिए)। रुचि रखने वाले किसी भी व्यक्ति के लिए, Activity खोलना या जैसे Dialogs जैसे तत्वों को शामिल करना संभव नहीं है। कुछ शोध के बाद मुझे एहसास हुआ कि अधिकतम जो आप प्रदान कर सकते हैं वह Toast संदेश है जो सर्वर को लॉग डिलीवरी को सूचित करता है।वैकल्पिक रूप से एक SharedPreferences अनुप्रयोग क्रैश इंगित करने के लिए इस्तेमाल किया जा सकता है, और आवेदन पुनः आरंभ करने पर, एक DialogSharedPreferences विशेषता मान के आधार पर और वहाँ से पहले पकड़ा अपवाद देने प्रदर्शित किया जा सकता (जाहिरा तौर पर अक्करा ही दृष्टिकोण का उपयोग करता):

public class FirstAc extends Activity{ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(); 

     sharedPrefValue = pref.getBoolean("DID_APP_CRASH", false); 
     if(sharedPrefValue) 
      dialog.show(); 
    } 
} 

StringWriter sw = new StringWriter(); 
PrintWriter pw = new PrintWriter(sw); 
exception.printStackTrace(pw); 
String stStr = sw.toString(); 
prefEditor.putString("EXCEPTION_CAUGHT", stStr); 

सारांश में, आदेश में एक दूरस्थ सर्वर से न आया हुआ अपवाद देने के लिए एक कस्टम UncaughtExceptionHandler बना सकते हैं और सबसे महत्वपूर्ण बात:

अपवाद है जब एप्लिकेशन निम्नलिखित कोड का टुकड़ा के साथ दुर्घटनाग्रस्त हो गया एक स्ट्रिंग के रूप में सहेजा जा सकता डिफ़ॉल्ट UncaughtExceptionHandler का संदर्भ रखें। System.exit() पर कॉल करके अचानक VM को बंद करने के बजाय कस्टम ऑपरेशन किए जाने के बाद एंड्रॉइड को अपवाद को संभालने के लिए और अधिक उचित है। क्रियान्वित कस्टम व्यवहार एंड्रॉयड डिफ़ॉल्ट ढंग से अपवाद संभालने दें के बाद

public class CustomApp extends Application { 

    @Override 
    public void onCreate() { 

     super.onCreate(); 
     Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this)); 
    } 
} 

CustomExceptionHandler के भीतर:: मैं Application तरफ अपवाद संचालक सेट पसंद करते हैं

public class CustomExceptionHandler implements UncaughtExceptionHandler { 

    private CustomApp    _app; 
    private UncaughtExceptionHandler _defaultEH; 

    public YolbilExceptionHandler(YolbilApp ac){ 

     _defaultEH = Thread.getDefaultUncaughtExceptionHandler(); 
     _app = ac; 
    } 

    @Override 
    public void uncaughtException(Thread thread, final Throwable ex) { 

     Toast.makeText(_app, "Delivering log...", Toast.LENGTH_LONG).show(); 
     // obtain the Exception info as a String 
     StringWriter sw = new StringWriter(); 
     PrintWriter pw = new PrintWriter(sw); 
     ex.printStackTrace(pw); 
     String exStr = sw.toString(); 
     ExceptionServer.getInstance().deliverMessageAsync(exStr, _app); 
     _defaultEH.uncaughtException(thread, ex); 
    } 

} 

और यहाँ एक नमूना कैसे करने के लिए है सर्वर पर एक संदेश को अतुल्य रूप से वितरित करें:

public void deliverMessageAsync(final String msg, final YolbilApp app){ 

    new Thread(new Runnable() { 

     @Override 
     public void run() { 

      HttpClient httpclient = new DefaultHttpClient(); 
      HttpPost httppost = new HttpPost(SERVER_ADDR); 
      try { 
       Looper.prepare(); 
       Toast.makeText(app, R.string.msg_delivering_log, Toast.LENGTH_LONG).show(); 
       httppost.setHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");     
       httpclient.execute(httppost); 
       Toast.makeText(app, "Log delivered ...", Toast.LENGTH_SHORT).show(); 
       Looper.loop(); 
      } catch (ClientProtocolException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    }).start(); 
}