Forma ideal de establecer la excepción global no detectada Handler en Android

Quiero configurar un controlador global de excepciones no detectadas para todos los hilos en mi aplicación Android. Por lo tanto, en mi subclase de Application establezco una implementación de Thread.UncaughtExceptionHandler como controlador predeterminado para las excepciones no detectadas.

 Thread.setDefaultUncaughtExceptionHandler( new DefaultExceptionHandler(this)); 

En mi implementación, bash mostrar un AlertDialog muestre el mensaje de excepción apropiado.

Sin embargo, esto no parece funcionar. Cada vez que se lanza una excepción para un hilo que no se maneja, obtengo el cuadro de diálogo estándar, OS-default (diálogo “Sorry! -Application-has-stopped-unexpectedly”).

¿Cuál es la forma correcta e ideal de establecer un controlador predeterminado para las excepciones no detectadas?

Eso debería ser todo lo que necesita hacer. (Asegúrese de hacer que el proceso se detenga después; las cosas podrían estar en un estado incierto).

Lo primero que debes comprobar es si aún se llama al controlador de Android. Es posible que se llame a su versión pero falle fatalmente y que system_server muestre un diálogo genérico cuando vea que el proceso falla.

Agregue algunos mensajes de registro en la parte superior de su controlador para ver si está llegando. Imprima el resultado de getDefaultUncaughtExceptionHandler y luego ejecute una excepción no detectada para provocar un locking. Esté atento a la salida de logcat para ver qué está pasando.

Publiqué la solución simple para el manejo personalizado de los lockings de Android hace mucho tiempo. Es un poco raro, pero funciona en todas las versiones de Android (incluido el Lollipop).

Primero un poco de teoría. Los problemas principales cuando utiliza el controlador de excepciones no detectadas en Android vienen con las excepciones lanzadas en el hilo principal (también conocido como UI). Y aquí está el por qué. Cuando la aplicación se inicia, el sistema llama al método ActivityThread.main que prepara e inicia el Looper principal de su aplicación:

 public static void main(String[] args) { … … Looper.prepareMainLooper(); … Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } 

Main Looper es responsable de procesar los mensajes publicados en el hilo de la interfaz de usuario (incluidos todos los mensajes relacionados con la representación e interacción de la interfaz de usuario). Si se lanza una excepción en el hilo de la interfaz de usuario, su manejador de excepciones lo detectará, pero como está fuera del método loop() no podrá mostrar ningún diálogo o actividad al usuario, ya que no queda nadie para procesar mensajes de UI por usted.

La solución propuesta es bastante simple. Looper.loop método Looper.loop por nuestra cuenta y lo rodeamos con un bloque try-catch. Cuando se Looper.loop una excepción, la procesamos como queremos (por ejemplo, comenzamos nuestra actividad de informe personalizado) y Looper.loop llamar Looper.loop método Looper.loop .

El siguiente método demuestra esta técnica (debe invocarse desde el oyente 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); } } } 

Como puede ver, el manejador de excepciones no detectadas se usa solo para las excepciones lanzadas en los hilos de fondo. El siguiente controlador detecta esas excepciones y las propaga al hilo de la interfaz de usuario:

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

Un proyecto de ejemplo que utiliza esta técnica está disponible en mi repository de GitHub: https://github.com/idolon-github/android-crash-catcher

FWIW Sé que esto está un poco fuera de tema, pero hemos estado usando el plan gratuito de Crittercism con éxito. También ofrecen algunas funciones premium, como manejar la excepción para que la aplicación no se cuelgue.

En la versión gratuita, el usuario todavía ve el locking, pero al menos recibo el correo electrónico y el seguimiento de la stack.

También usamos la versión de iOS (pero he escuchado de mis colegas que no es tan buena).


Aquí hay preguntas similares:

  • Controlador global de excepciones no detectadas -> correo electrónico de registro para mí?
  • ¿Es posible crear algún tipo de manejador de excepciones globales en Android?

Creo que para deshabilitar eso en su método uncaughtException () no llame a previousHandler.uncaughtException () donde se establece previousHandler

 previousHandler = Thread.getDefaultUncaughtExceptionHandler(); 

No funciona hasta que llame

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

al final de su UncaughtExceptionHandler.