8

Estoy usando este código para controlar cualquier excepción no detectada que pueda causar el bloqueo de mi aplicación.Toast no aparece en UnCaughtExceptionHandler

public class ExceptionHandler implements java.lang.Thread.UncaughtExceptionHandler { 
    private final Context myContext; 

    public ExceptionHandler(Context context) { 

     myContext = context; 
    } 

    public void uncaughtException(Thread thread, Throwable exception) { 

     Toast.makeText(myContext, 
       "The application has crashed, and a report is sent to the admin", 
       Toast.LENGTH_SHORT).show(); 
     StringWriter stackTrace = new StringWriter(); 
     exception.printStackTrace(new PrintWriter(stackTrace)); 
     System.err.println(stackTrace);// You can use LogCat too 
     Intent intent = new Intent(myContext, CrashActivity.class); 
     myContext.startActivity(intent); 
     Process.killProcess(Process.myPid()); 
     System.exit(10); 
    } 
} 

Cuando lo funciono con una excepción conocida, pero no detectada (sólo para probar), la actividad "CrashActivity" se llama, pero la tostada que debe venir antes de que no se muestra.

En realidad, quería mostrar solo Toast y luego llamar a myContext.finish(); en lugar de ir a CrashActivity. Pero esa tostada no es visible.

¿Dónde estoy equivocado?

+2

No soy un programador de Android, pero según la lectura que he hecho, ¿no se debe llamar a Toast en el hilo de la interfaz de usuario? En ese caso, ¿lo está invocando en el hilo de UI? Supongo que probablemente ya hayas pensado en esto. –

+0

sí, tienes razón ... no estoy llamando la atención sobre el hilo de la interfaz de usuario :( –

Respuesta

3

Usted probablemente está llamando la tostada de un hilo, mientras que una tostada se debe llamar desde el hilo de interfaz de usuario ...

Si esto no ayuda, por favor proporcionar la salida Logcat para que podamos ver qué tipo de error que está recibiendo

+0

Sí, estoy equivocado al usar Toast en un hilo diferente. En realidad, lo vi en una aplicación donde cuando la aplicación se bloquea muestra un brindis en el misma actividad. ¿Es que realmente recuerda la misma actividad y luego muestra el brindis? –

7

Encontró esta pregunta mientras buscaba en Google exactamente el mismo problema. Por lo que puedo decir, no es necesario tener el Toast.show() llamado desde el subproceso de interfaz de usuario, siempre que haya un contexto de aplicación.

AFAIK: El problema que aparece aquí es el siguiente: Estás tratando de mostrar un Toast e inmediatamente después tu aplicación se cierra por la VM, lo que significa que tu Toast también está apagado.

Una solución para el problema es el siguiente:

  • Ejecutar la tostada de un hilo sepearate
  • apagado retraso de su aplicación en el controlador de excepciones.

Lo que hago es la siguiente:

En Application::onCreate():

Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { 
    @Override 
    public void uncaughtException(Thread thread, Throwable ex) 
    { 
     new Thread() { 
      @Override 
      public void run() { 
       Looper.prepare(); 
       Toast.makeText(getApplicationContext(), "Application crashed", Toast.LENGTH_LONG).show(); 
       Looper.loop(); 
      } 
     }.start(); 

     try 
     { 
      Thread.sleep(4000); // Let the Toast display before app will get shutdown 
     } 
     catch (InterruptedException e) 
     { 
      // Ignored. 
     } 
    } 
}); 

Es similar a la forma en la notificación de la tostada en ACRA trabaja (de hecho, este es el lugar donde me dieron el toque de) .

+0

Esto era justo lo que necesitaba ya que quería una forma rápida (temporal) de ver algunos detalles de la excepción. Encontré que también tenía que poner en una llamada 'System.exit()' después del bloque 'catch'.¿Falta esto en lo de arriba? – darrenp

+0

Pjuh. Buena pregunta. No salgo con 'System.exit()' pero utilizo el manejador de excepciones predeterminado con '_androidDefaultUncaughtExHandler.uncaughtException (thread, ex);' y lo configuro con '_androidDefaultUncaughtExHandler = Thread.getDefaultUncaughtExceptionHandler();' – GeneSys

+1

Tiene sentido. El controlador de excepción predeterminado debe estar ordenando y llamando a 'System.exit()'. – darrenp

3

Llamar System.exit(0) desde Android UncaughtExceptionHandler ayuda a la aplicación a recuperarse del error y reiniciar la última actividad. En mi humilde opinión, la experiencia del usuario se mejora significativamente. Sin embargo, este enfoque debe probarse y probarse en múltiples plataformas de Android. He intentado esto con GB y JB. Funcionó bien Además, escuché de otros (soy nuevo en Android) que invocar System.exit() no se recomienda en Android pero ... podría usar esto como una buena opción de recuperación para bloqueos de aplicaciones de Android.

public void uncaughtException(Thread thread, Throwable ex) { 
     new Thread() { 
      @Override 
      public void run() { 
       Looper.prepare(); 
       Toast.makeText(YourActivity.this, "Application has Crashed. Recovering now.", Toast.LENGTH_LONG).show(); 
       /* Log relevant message/analytics from here. */ 
       System.exit(1); 
       Looper.loop(); 
      } 
     }.start(); 
    } 
+0

¿Cómo puedo evitar el reinicio de la aplicación cuando llamo a System.exit()? Quiero que la aplicación se cierre realmente cuando hay un bloqueo, pero quiero capturar el evento y enviar los datos por correo electrónico ... –

+0

'System.exit()' cerrará la aplicación abruptamente en la mayoría de los casos, lo cual es generalmente no es lo que quieres La aplicación se bloqueará si llama a 'exit()' o no, por lo que no hay necesidad real de llamarlo de manera explícita. – milosmns