java - tipos - try catch para que sirve
Usar try/catch para evitar que la aplicaciĆ³n se bloquee (14)
Como se dijo antes, las excepciones generales no deben ser detectadas, o al menos solo en algunos lugares centrales (generalmente ubicados en el marco / código de infraestructura, no en el código de la aplicación). Si se detectan excepciones generales y se registra, la aplicación debe cerrarse después o, como mínimo, el usuario debe ser informado de que la aplicación está potencialmente en un estado inestable y podría producirse corrupción de datos (si el usuario elige continuar la ejecución). Porque esto es lo que podría suceder si detecta todo tipo de excepciones (sin memoria para nombrar una) y deja la aplicación en un estado indefinido.
En mi humilde opinión, es peor tragar excepciones y arriesgar la integridad de los datos, la pérdida de datos o simplemente dejar la aplicación en un estado indefinido que dejar que la aplicación se bloquee y el usuario sepa que algo salió mal y puede intentarlo nuevamente. Esto también conducirá a mejores problemas informados (más en la raíz del problema), probablemente menos síntomas diferentes que si sus usuarios comienzan a informar todo tipo de problemas que se originan en un estado de aplicación indefinido.
Después de un manejo / registro / informe central de excepciones y un apagado controlado, comience a reescribir el manejo de excepciones para capturar excepciones locales lo más específico posible. Intenta hacer que el bloque try {} sea lo más corto posible.
He estado trabajando en una aplicación de Android que usa
try/catch
frecuencia para evitar que se bloquee incluso en lugares donde no hay necesidad.
Por ejemplo,
Se hace referencia a una vista en
xml layout
con
id = toolbar
como:
// see new example below, this one is just confusing
// it seems like I am asking about empty try/catch
try {
View view = findViewById(R.id.toolbar);
}
catch(Exception e) {
}
Este enfoque se utiliza en toda la aplicación. El seguimiento de la pila no se imprime y es realmente difícil encontrar lo que salió mal. La aplicación se cierra repentinamente sin imprimir ningún rastro de pila.
Le pedí a mi superior que me lo explicara y él dijo:
Esto es para evitar accidentes en la producción.
Estoy totalmente en desacuerdo con eso . Para mí, esta no es la forma de evitar que las aplicaciones se bloqueen. Muestra que el desarrollador no sabe lo que está haciendo y tiene dudas.
¿Es este el enfoque utilizado en la industria para evitar que las aplicaciones empresariales se bloqueen?
Si
try/catch
es realmente nuestra verdadera necesidad, ¿es posible adjuntar un controlador de excepción con un hilo de interfaz de usuario u otros hilos y capturar todo allí?
Será un mejor enfoque si es posible.
Sí, el
try/catch
vacío es malo e incluso si imprimimos el seguimiento de la pila o la excepción de registro al servidor, envolver bloques de código en
try/catch
aleatoriamente en toda la aplicación no tiene sentido para mí, por ejemplo, cuando cada función está encerrada en un
try/catch
.
ACTUALIZAR
Como esta pregunta ha recibido mucha atención y algunas personas han malinterpretado la pregunta (tal vez porque no la he expresado claramente) voy a reformularla.
Esto es lo que los desarrolladores están haciendo aquí.
-
Una función se escribe y se prueba , puede ser una función pequeña que solo inicializa vistas o una compleja, después de probarla se envuelve alrededor del bloque
try/catch
. Incluso para una función que nunca arrojará ninguna excepción. -
Esta práctica se usa en toda la aplicación. En algún momento se imprime el seguimiento de la pila y, a veces, solo un
debug log
con algún mensaje de error aleatorio. Este mensaje de error difiere de un desarrollador a otro. -
Con este enfoque, la aplicación no se bloquea, pero el comportamiento de la aplicación se vuelve indeterminado. Incluso a veces es difícil seguir lo que salió mal.
-
La verdadera pregunta que he estado haciendo fue; ¿Es la práctica que se sigue en la industria para evitar que las aplicaciones empresariales se bloqueen? y no estoy preguntando sobre try / catch vacío . ¿Es como, a los usuarios les encantan las aplicaciones que no se bloquean que las aplicaciones que se comportan inesperadamente? Porque realmente se reduce a colapsarlo o presentarle al usuario una pantalla en blanco o el comportamiento que el usuario desconoce.
-
Estoy publicando algunos fragmentos del código real aquí.
private void makeRequestForForgetPassword() { try { HashMap<String, Object> params = new HashMap<>(); String email= CurrentUserData.msisdn; params.put("email", "blabla"); params.put("new_password", password); NetworkProcess networkProcessForgetStep = new NetworkProcess( serviceCallListenerForgotPasswordStep, ForgotPassword.this); networkProcessForgetStep.serviceProcessing(params, Constants.API_FORGOT_PASSWORD); } catch (Exception e) { e.printStackTrace(); } } private void languagePopUpDialog(View view) { try { PopupWindow popupwindow_obj = popupDisplay(); popupwindow_obj.showAsDropDown(view, -50, 0); } catch (Exception e) { e.printStackTrace(); } } void reloadActivity() { try { onCreateProcess(); } catch (Exception e) { } }
No es un duplicado de las mejores prácticas de manejo de excepciones de Android , OP está tratando de detectar excepciones para un propósito diferente al de esta pregunta.
De la documentación de Android :
Vamos a titularlo como ...
No atrape la excepción genérica
También puede ser tentador ser flojo al detectar excepciones y hacer algo como esto:
try { someComplicatedIOFunction(); // may throw IOException someComplicatedParsingFunction(); // may throw ParsingException someComplicatedSecurityFunction(); // may throw SecurityException // phew, made it all the way } catch (Exception e) { // I''ll just catch all exceptions handleError(); // with one generic handler! }
En casi todos los casos, es inapropiado detectar
Exception
genérica o Lanzable (preferiblemente no Lanzable porque incluye excepciones de Error). Es muy peligroso porque significa que las excepciones que nunca esperaba (incluidas las excepciones de tiempo deRuntimeExceptions
comoClassCastException
) quedan atrapadas en el manejo de errores a nivel de aplicación.Oculta las propiedades de manejo de fallas de su código, lo que significa que si alguien agrega un nuevo tipo de
Exception
en el código que está llamando, el compilador no lo ayudará a darse cuenta de que necesita manejar el error de manera diferente .
Alternativas a la captura de la excepción genérica:
- Capture cada excepción por separado como bloques de captura separados después de un solo intento. Esto puede ser incómodo, pero sigue siendo preferible a la captura de todas las excepciones.
Editar por autor: Esta es mi elección. Tenga cuidado de repetir demasiado código en los bloques catch. Si está utilizando Java 7 o superior, use la captura múltiple para evitar repetir el mismo bloque de captura.- Refactorice su código para tener un manejo de errores más detallado , con múltiples bloques de prueba. Divida el IO del análisis, maneje los errores por separado en cada caso.
- Vuelve a lanzar la excepción . Muchas veces no necesitas atrapar la excepción a este nivel de todos modos, solo deja que el método la arroje.
En la mayoría de los casos, no debería manejar diferentes tipos de excepción de la misma manera.
Formateo / párrafo ligeramente modificado de la fuente para esta respuesta.
PD: ¡No tengas miedo de las excepciones! ¡¡¡Ellos son amigos!!!
Definitivamente es una mala práctica de programación.
Desde el escenario actual, si hay cientos de
try
catch
como este, entonces ni siquiera sabrá dónde ocurre la excepción sin depurar la aplicación, lo cual es una pesadilla si su aplicación está en un entorno de producción.
Pero puede incluir un registrador para saber cuándo se produce una excepción (y por qué). No cambiará su flujo de trabajo normal.
...
try {
View view = findViewById(R.id.toolbar);
}catch(Exception e){
logger.log(Level.SEVERE, "an exception was thrown", e);
}
...
Es una mala práctica usar
catch(Exception e){}
porque esencialmente estás ignorando el error.
Lo que probablemente quieras hacer es algo más como:
try {
//run code that could crash here
} catch (Exception e) {
System.out.println(e.getMessage());
}
Esta es una mala práctica. Otras respuestas han dicho eso, pero creo que es importante dar un paso atrás y comprender por qué tenemos excepciones en primer lugar.
Cada función tiene una condición posterior : un conjunto de cosas que deben ser ciertas después de que se ejecute esa función. Por ejemplo, una función que lee de un archivo tiene la condición de publicación de que los datos del archivo se leerán del disco y se devolverán. Entonces, se produce una excepción cuando una función no ha podido satisfacer una de sus condiciones posteriores.
Al ignorar una excepción de una función (o incluso ignorarla efectivamente simplemente registrando la excepción), está diciendo que está de acuerdo con que esa función no esté haciendo todo el trabajo que acordó hacer. Esto parece poco probable: si una función no se ejecuta correctamente, no hay garantía de que lo que sigue se ejecute en absoluto. Y si el resto de su código funciona bien, ya sea que una función en particular se ejecute o no, entonces uno se pregunta por qué tiene esa función en primer lugar.
[Ahora hay ciertos casos donde las
catch
vacías están bien.
Por ejemplo, el registro es algo que puede justificar envolver en una captura vacía.
Su aplicación probablemente funcionará bien incluso si parte del registro no se puede escribir.
Pero esos son casos especiales en los que tienes que trabajar muy duro para encontrarlos en una aplicación normal.]
Entonces, el punto es que esta es una mala práctica porque en realidad no mantiene su aplicación en funcionamiento (la supuesta justificación de este estilo). Tal vez técnicamente el sistema operativo no lo ha matado. Pero es poco probable que la aplicación siga funcionando correctamente después de ignorar una excepción. Y en el peor de los casos, podría estar haciendo daño (por ejemplo, corromper archivos de usuario, etc.).
Esto es malo por múltiples razones:
-
¿Qué haces para que
findViewById
arroje una excepción? Arregla eso (y dime, porque nunca he visto esto) en lugar de atraparlo. -
No atrape
Exception
cuando podría atrapar un tipo específico de excepción. - Existe la creencia de que las buenas aplicaciones no fallan. Eso no es cierto. Una buena aplicación se bloquea si es necesario.
Si una aplicación entra en un mal estado, es mucho mejor que se bloquee que siga avanzando en su estado inutilizable. Cuando uno ve un NPE, uno no debería quedarse con un cheque nulo y marcharse. El mejor enfoque es descubrir por qué algo es nulo y evitar que sea nulo o (si nulo termina siendo un estado válido y esperado) verificar si es nulo. Pero debes entender por qué el problema ocurre en primer lugar.
He estado desarrollando aplicaciones de Android durante los últimos 4-5 años y nunca utilicé una prueba de captura para la inicialización de la vista.
Si es una barra de herramientas, haz esto
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
por ejemplo: - Para obtener un TextView desde una vista (fragmento / diálogo / cualquier vista personalizada)
TextView textview = (TextView) view.findViewById(R.id.viewId);
TextView textview = (TextView) view.findViewById (R.id.viewId);
en lugar de esto
View view = findViewById(R.id.toolbar);
Un objeto de vista tiene un alcance mínimo en comparación con su tipo de vista real.
Nota: - Puede que se bloquee porque se cargó la vista. Pero agregar try catch es una mala práctica.
Otra perspectiva, como alguien que escribe software empresarial diariamente, si una aplicación tiene un error irrecuperable, quiero que se bloquee. Chocar es deseable. Si se bloquea, se registra. Si se bloquea más de unas pocas veces en un corto período de tiempo, recibo un correo electrónico que dice que la aplicación se está bloqueando y puedo verificar que nuestra aplicación y todos los servicios web que consumimos siguen funcionando.
Entonces la pregunta:
Es
try{
someMethod();
}catch(Exception e){}
¿buena práctica? ¡No! Aquí hay algunos puntos:
-
Lo más importante: esta es una mala experiencia del cliente. ¿Cómo se supone que debo saber cuando algo malo está sucediendo? Mis clientes están tratando de usar mi aplicación y nada funciona. No pueden verificar su cuenta bancaria, pagar sus facturas, haga lo que haga mi aplicación. Mi aplicación es completamente inútil, pero bueno, ¡al menos no se bloqueó! (Una parte de mí cree que este desarrollador "Senior" obtiene puntos de brownie por números bajos de fallas, por lo que están jugando con el sistema).
-
Cuando estoy desarrollando y escribo código incorrecto, si solo estoy captando y tragando todas las excepciones en la capa superior, no tengo registro. No tengo nada en mi consola y mi aplicación falla en silencio. Por lo que puedo decir, todo parece funcionar bien. Así que confirmo el código ... Resulta que mi objeto DAO fue nulo todo el tiempo, y los pagos del cliente nunca se actualizaron en la base de datos. Whoops! Pero mi aplicación no se bloqueó, así que eso es una ventaja.
-
Jugando al abogado del diablo, digamos que estaba de acuerdo con atrapar y tragar cada excepción. Es extremadamente fácil escribir un controlador de excepciones personalizado en Android. Si realmente tiene que atrapar todas las excepciones, puede hacerlo en un solo lugar y no
try/catch
toda su base de código.
Algunos de los desarrolladores con los que he trabajado en el pasado han pensado que fallar era malo.
Tengo que asegurarles que queremos que nuestra aplicación se bloquee. No, una aplicación inestable no está bien, pero un bloqueo significa que hicimos algo mal y tenemos que solucionarlo. Cuanto más rápido se bloquea, antes lo encontramos, más fácil es arreglarlo. La única otra opción que se me ocurre es permitir que el usuario continúe en una sesión interrumpida, lo que equiparo con cabrear mi base de usuarios.
Permítanme agregar mi punto de vista, como un hombre que trabaja en la industria de desarrollo móvil corporativo durante más de una década. Primero, algunos consejos generales sobre excepciones, la mayoría de ellos incluidos en las respuestas anteriores:
- Las excepciones deben usarse para situaciones excepcionales, inesperadas o no controladas, no de forma regular en todo el código.
- Un programador debe conocer las porciones de código susceptibles de generar excepciones e intentar atraparlas, dejando el resto del código lo más limpio posible.
- Las excepciones no deben quedar en silencio, como regla general.
Ahora, cuando no está desarrollando una aplicación para usted, sino para una empresa o corporación, es común enfrentar requisitos adicionales sobre este tema:
- "Los bloqueos de aplicaciones muestran una imagen pobre de la empresa, por lo que no son aceptables". Entonces, se debe realizar un desarrollo cuidadoso, y capturar incluso excepciones improbables puede ser una opción. Si es así, esto debe hacerse de forma selectiva y mantenerse en límites razonables. Y observe que el desarrollo no se trata solo de líneas de código, por ejemplo, un proceso de prueba intensivo es crítico en estos casos. Sin embargo, el comportamiento inesperado en una aplicación corporativa es peor que fallar. Entonces, cada vez que detecte una excepción en su aplicación, debe saber qué hacer, qué mostrar y cómo se comportará la aplicación a continuación. Si no puede controlar eso, mejor deje que la aplicación se bloquee.
- "Los registros y los seguimientos de pila pueden volcar información confidencial en la consola. Eso podría usarse para un atacante, por lo que por razones de seguridad no pueden usarse en un entorno de producción". Este requisito entra en conflicto con la regla general para que un desarrollador no escriba excepciones silenciosas, por lo que debe encontrar la manera de hacerlo. Por ejemplo, su aplicación podría controlar el entorno, por lo que utiliza registros y seguimientos de pila en entornos que no son de producción, al tiempo que utiliza herramientas basadas en la nube como detección de errores, crashlitics o similares para entornos de producción.
Por lo tanto, la respuesta breve es que el código que encontró no es un ejemplo de buena práctica, ya que es difícil y costoso de mantener sin mejorar la calidad de la aplicación.
Pondría esto como un comentario a alguna otra respuesta, pero todavía no tengo la reputación de eso.
Tienes razón al decir que es una mala práctica, de hecho, lo que publicaste muestra diferentes tipos de malas prácticas con respecto a las excepciones.
- Falta de manejo de errores
- Captura Genérica
- No hay excepciones intencionales.
- Manta Try / catch
Trataré de explicar todo eso a través de este ejemplo.
try {
User user = loadUserFromWeb();
if(user.getCountry().equals("us")) {
enableExtraFields();
}
fillFields(user);
} catch (Exception e) {
}
Esto puede fallar de varias maneras que se deben manejar de manera diferente.
- Los campos no se completarán, por lo que se le presenta al usuario una pantalla vacía y luego ... ¿qué? Nada: falta de manejo de errores.
- No hay distinción entre los diferentes tipos de errores, por ejemplo, problemas de Internet o problemas con el servidor en sí (corte, solicitud interrumpida, transmisión corrupta, ...) - Captura genérica.
- No puede usar excepciones para sus propios fines porque el sistema actual interfiere con eso. - Sin excepciones intencionales
- Errores no esenciales e inesperados (por ejemplo, null.equals (...)) pueden hacer que el código esencial no se ejecute. - Prueba / captura combinada
Soluciones
(1) En primer lugar, fallar en silencio no es algo bueno. Si hay una falla, la aplicación no funcionará. En su lugar, debería haber un intento de resolver el problema o mostrar una advertencia, por ejemplo, "¿No se pudieron cargar los datos del usuario, tal vez no está conectado a Internet?". Si la aplicación no está haciendo lo que se supone que debe hacer, eso es mucho más frustrante para un usuario que si simplemente se cierra.
(4) Si el usuario está incompleto, por ejemplo, el país no se conoce y devuelve nulo. El método igual creará una NullPointerException. Si ese NPE solo se lanza y se atrapa como se indicó anteriormente, no se llamará al método fillFields (usuario), aunque aún podría ejecutarse sin problemas. Puede evitar esto incluyendo verificaciones nulas, cambiando el orden de ejecución o ajustando el alcance try / catch. (O podría guardar la codificación de esta manera: "nosotros" .equals (user.getCountry ()), pero tuve que proporcionar un ejemplo). Por supuesto, cualquier otra excepción también evitará que se ejecuten fillFields (), pero si no hay ningún usuario, probablemente no quiera que se ejecute de todos modos.
(1, 2, 3) La carga desde la web a menudo arroja una variedad de excepciones, desde IOException hasta la excepción HttpMessageNotReadable, incluso hasta el regreso. Podría ser que el usuario no esté conectado a Internet, podría ser que hubo un cambio en un servidor de fondo o está inactivo, pero no lo sabe porque detecta (Excepción); en su lugar, debe detectar excepciones específicas. Incluso puedes atrapar a varios de ellos así
try{
User user = loadUserFromWeb(); //throws NoInternetException, ServerNotAvailableException or returns null if user does not exist
if(user == null) {
throw new UserDoesNotExistException(); //there might be better options to solve this, but it highlights how exceptions can be used.
}
fillFields(user);
if("us".equals(user.getCountry()) {
enableExtraFields();
}
} catch(NoInternetException e){
displayWarning("Your internet conneciton is down :(");
} catch(ServerNotAvailableException e){
displayWarning("Seems like our server is having trouble, try again later.");
} catch(UserDoesNotExistException e){
startCreateUserActivity();
}
Espero que esto lo explique.
Como mínimo, como solución rápida, lo que puede hacer es enviar un evento a su backend con la excepción. Por ejemplo a través de firebase o crashlytics. De esa manera, al menos puede ver cosas como (oye, la actividad principal no se carga para el 80% de nuestros usuarios debido a un problema como (4).
Por supuesto, siempre hay excepciones a las reglas, pero si necesita una regla general, entonces está en lo correcto; los bloques de captura vacíos son "absolutamente" una mala práctica.
Echemos un vistazo más de cerca, primero comenzando con su ejemplo específico:
try {
View view = findViewById(R.id.toolbar);
}
catch(Exception e) { }
Entonces, se crea una referencia a algo; y cuando eso falla ... no importa; ¡porque esa referencia no se usa en primer lugar! El código anterior es un ruido de línea absolutamente inútil . ¿O la persona que escribió ese código inicialmente supone que una segunda llamada similar mágicamente ya no arrojaría una excepción?
Tal vez esto debía verse así:
try {
View view = findViewById(R.id.toolbar);
... and now do something with that view variable ...
}
catch(Exception e) { }
Pero de nuevo, ¿qué ayuda esto? Existen excepciones para comunicar, respectivamente, situaciones de error de propagación dentro de su código. Ignorar los errores rara vez es una buena idea. En realidad, una excepción puede tratarse de la siguiente manera:
- Usted le da retroalimentación al usuario; (como: "el valor que ingresó no es una cadena, intente nuevamente"); o participar en un manejo de errores más complejo
- Tal vez el problema se espera de alguna manera y se puede mitigar (por ejemplo, dando una respuesta "predeterminada" cuando falla alguna "búsqueda remota")
- ...
Larga historia corta: lo mínimo que haces con una excepción es registrarlo / rastrearlo; para que cuando llegues a depurar algún problema entiendas "OK, en este momento sucedió esa excepción".
Y como otros han señalado: también evitas atrapar Exception en general (bueno, dependiendo de la capa: puede haber buenas razones para atrapar Exception e incluso algunos tipos de Errores al más alto nivel, para asegurarte de que nada se pierde; nunca ).
Finalmente, quote Ward Cunningham:
Sabes que estás trabajando con código limpio cuando cada rutina que lees resulta ser más o menos lo que esperabas. Puede llamarlo código hermoso cuando el código también hace que parezca que el idioma fue creado para el problema.
Deja que eso se hunda y medite al respecto. El código limpio no te sorprende. El ejemplo que nos está mostrando sorprende a todos los que lo ven.
Actualización , con respecto a la actualización que el OP pregunta
try {
do something
}
catch(Exception e) {
print stacktrace
}
La misma respuesta: hacer eso "por todas partes" también es una mala práctica. Porque este código también sorprende al lector.
Lo anterior:
- Imprime información de error en alguna parte. No se garantiza en absoluto que este "lugar" se parezca a un destino razonable . De lo contrario. Ejemplo: dentro de la aplicación con la que estoy trabajando, tales llamadas aparecerían mágicamente en nuestros búferes de rastreo. Dependiendo del contexto, nuestra aplicación puede bombear toneladas y toneladas de datos a esos búferes a veces; haciendo que los tampones se poden cada pocos segundos. Entonces, "simplemente imprimir errores" a menudo se traduce en: "simplemente perder toda esa información de error".
- Entonces: no intentas / atrapas porque puedes. Lo haces porque entiendes lo que está haciendo tu código; y ya sabes: es mejor que intente / atrape aquí para hacer lo correcto (vea las primeras partes de mi respuesta nuevamente).
Entonces, usando try / catch como "patrón" como lo estás mostrando; es como se dijo: todavía no es una buena idea. Y sí, evita accidentes; pero conduce a todo tipo de comportamiento "indefinido". Ya sabes, cuando solo atrapas una excepción en lugar de tratarla adecuadamente ; abres una lata de gusanos; porque podrías encontrarte con miles de errores de seguimiento que luego no entiendes. Porque consumió el evento "causa raíz" anteriormente; lo imprimí en alguna parte; y ese lugar ahora se ha ido.
Sí, try / catch se usa para evitar que la aplicación se bloquee, pero ciertamente no necesita try / catch para obtener una vista desde XML como se muestra en su pregunta.
try / catch se usa generalmente al realizar cualquier solicitud http, al analizar cualquier Cadena a URL, crear conexiones URL, etc. y también asegurarse de imprimir el seguimiento de la pila. No imprimir no tiene mucho sentido rodearlo con try / catch.
Si bien estoy de acuerdo con las otras respuestas, hay una circunstancia que he encontrado repetidamente donde este motivo es marginalmente tolerable. Supongamos que alguien escribe un poco de código para una clase de la siguiente manera:
private int foo=0;
. . .
public int getFoo() throws SomeException { return foo; }
En esta circunstancia, el método ''getFoo ()'' no puede fallar : siempre habrá un valor legítimo del campo privado ''foo'' que se devolverá. Sin embargo, alguien, probablemente por razones pedantes, decidió que este método debería declararse como una posible excepción. Si luego intenta llamar a este método en un contexto, por ejemplo, un controlador de eventos, que no permite que se produzca una excepción, básicamente se ve obligado a usar esta construcción (incluso entonces, estoy de acuerdo en que uno debería al menos registrar la excepción solo en caso) Siempre que tengo que hacer esto, al menos siempre agrego un comentario grande y gordo ''ESTO NO PUEDE OCURRIR'' al lado de la cláusula ''catch''.
Usamos bastante tu misma lógica.
Use
try-catch
para evitar que las aplicaciones de producción se bloqueen.
Las excepciones NUNCA deben ignorarse. Es una mala práctica de codificación. Los chicos que mantienen el código tendrán dificultades para localizar la parte del código que generó la excepción si no están registrados.
Usamos
Crashlytics
para registrar las excepciones.
El código no se bloqueará (pero se interrumpirá alguna funcionalidad).
Pero obtienes el registro de excepciones en el panel de control de
Fabric/Crashlytics
.
Puede mirar estos registros y corregir las excepciones.
try {
codeThatCouldRaiseError();
} catch (Exception e) {
e.printStackTrace();
Crashlytics.logException(e);
}