Show a dialog in `Thread.setDefaultUncaughtExceptionHandler`

后端 未结 2 1253
再見小時候
再見小時候 2021-02-01 22:42

When my android application throw an exception, I want to show a custom dialog to tell user there is something wrong happened, so I use Thread.setDefaultUncaughtExceptionH

2条回答
  •  抹茶落季
    2021-02-01 23:46

    It seems that the solution provided does not work (at least for Android 4.0 and above). For anyone who might be interested, opening an Activity or involving some sort of UI elements such as Dialogs is not possible. After some research i realized that the maximum you can provide is a Toast message notifying the log delivery to the server. Optionally a SharedPreferences can be used to indicate the application crash, and on the application restart, a Dialog can be displayed based on the SharedPreferences attribute value and from there deliver the previously caught exception (apparently Accra uses the same approach):

    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();
        }
    }
    

    The exception can be saved as a string when the app crashed with the following code snippet:

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

    To sum up, in order to deliver the uncaught exception to a remote server create a custom UncaughtExceptionHandler and most importantly keep a reference to the default UncaughtExceptionHandler. Instead of abruptly shutting down the VM by calling System.exit() it is more reasonable to let Android handle the exception after the custom operations are performed. I prefer set the exception handler on the Application side:

    public class CustomApp extends Application {
    
        @Override
        public void onCreate() {
    
            super.onCreate();
            Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(this));
        }
    }
    

    Within the CustomExceptionHandler after executing the custom behaviour let Android handle the exception in the default manner:

    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);
        }
    
    }
    

    And here is a sample how to deliver asynchronously a message to server:

    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();
    }
    

提交回复
热议问题