141 votos

AsyncTask y manejo de errores en Android

Estoy convirtiendo mi código de usar Handler a AsyncTask . Este último es genial en lo que hace - actualizaciones asíncronas y manejo de resultados en el hilo principal de la UI. Lo que no me queda claro es cómo manejar las excepciones si algo se descontrola en AsyncTask#doInBackground .

La forma en que lo hago es tener un manejador de errores y enviarle mensajes. Funciona bien, pero ¿es el enfoque "correcto" o hay alguna alternativa mejor?

También entiendo que si defino el manejador de errores como un campo de actividad, debería ejecutarse en el hilo de la interfaz de usuario. Sin embargo, a veces (muy impredeciblemente) obtendré una Excepción diciendo que el código disparado desde Handler#handleMessage se está ejecutando en el hilo equivocado. ¿Debo inicializar el manejador de errores en Activity#onCreate ¿en su lugar? Colocación de runOnUiThread en Handler#handleMessage parece redundante pero se ejecuta de forma muy fiable.

170voto

CommonsWare Puntos 402670

Funciona bien, pero ¿es el enfoque "correcto"? enfoque y hay una mejor alternativa?

Me aferro a la Throwable o Exception en el AsyncTask y luego hacer algo con ella en onPostExecute() Así que mi manejo de errores tiene la opción de mostrar un diálogo en la pantalla.

127voto

Cagatay Kalan Puntos 1489

Crea un objeto AsyncResult ( que también puedes utilizar en otros proyectos)

public class AsyncTaskResult<T> {
private T result;
private Exception error;

public T getResult() {
    return result;
}
public Exception getError() {
    return error;
}

public AsyncTaskResult(T result) {
    super();
    this.result = result;
}

public AsyncTaskResult(Exception error) {
    super();
    this.error = error;
}
}

Devuelve este objeto desde sus métodos AsyncTask doInBackground y lo comprueba en el postExecute. ( Puedes usar esta clase como clase base para tus otras tareas asíncronas)

A continuación se muestra una maqueta de una tarea que obtiene una respuesta JSON del servidor web.

AsyncTask<Object,String,AsyncTaskResult<JSONObject>> jsonLoader = new AsyncTask<Object, String, AsyncTaskResult<JSONObject>>() {

        @Override
        protected AsyncTaskResult<JSONObject> doInBackground(
                Object... params) {
            try {
                // get your JSONObject from the server
                return new AsyncTaskResult<JSONObject>(your json object);
            } catch ( Exception anyError) {
                return new AsyncTaskResult<JSONObject>(anyError);
            }
        }

        protected void onPostExecute(AsyncTaskResult<JSONObject> result) {
            if ( result.getError() != null ) {
                // error handling here
            }  else if ( isCancelled()) {
                // cancel handling here
            } else {

                JSONObject realResult = result.getResult();
                // result handling here
            }
        };

    }

10voto

sulai Puntos 1264

Cuando siento la necesidad de manejar excepciones en AsyncTask correctamente, uso esto como super clase:

public abstract class ExceptionAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    private Exception exception=null;
    private Params[] params;

    @Override
    final protected Result doInBackground(Params... params) {
        try {
            this.params = params; 
            return doInBackground();
        }
        catch (Exception e) {
            exception = e;
            return null;
        }
    }

    abstract protected Result doInBackground() throws Exception;

    @Override
    final protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        onPostExecute(exception, result);
    }

    abstract protected void onPostExecute(Exception exception, Result result);

    public Params[] getParams() {
        return params;
    }

}

Como es normal, se anula doInBackground en su subclase para hacer el trabajo de fondo, lanzando felizmente Excepciones cuando sea necesario. A continuación, se ve obligado a implementar onPostExecute (porque es abstracto) y esto le recuerda suavemente que debe manejar todo tipo de Exception que se pasan como parámetro. En la mayoría de los casos, las excepciones conducen a algún tipo de salida ui, por lo que onPostExecute es un lugar perfecto para hacerlo.

5voto

ludwigm Puntos 1751

Si quieres utilizar el framework RoboGuice que te aporta otras ventajas puedes probar el RoboAsyncTask que tiene un Callback onException() extra. Funciona muy bien y yo lo uso. http://code.google.com/p/roboguice/wiki/RoboAsyncTask

2voto

Ali Puntos 1597

Otra forma que no depende del reparto de miembros variables es utilizar la cancelación.

Esto es de los documentos de Android:

public final boolean cancel (boolean mayInterruptIfRunning)

Intenta cancelar la ejecución de esta tarea. Este intento de intento fallará si la tarea ya se ha completado, ya ha sido ya ha sido cancelada, o no ha podido ser cancelada por alguna otra razón. Si Si tiene éxito, y esta tarea no se ha iniciado cuando se llama a la cancelación, esta tarea no debería ejecutarse nunca. Si la tarea ya se ha iniciado, la función parámetro mayInterruptIfRunning determina si el hilo que ejecuta esta tarea debe ser interrumpido en un intento de detener la tarea.

Al llamar a este método se invoca onCancelled(Object) en el hilo de la interfaz de usuario después de que doInBackground(Object[]) regrese. Llamar a este método garantiza que onPostExecute(Object) nunca sea invocado. Después de después de invocar este método, debe comprobar el valor devuelto por isCancelled() periódicamente desde doInBackground(Object[]) para terminar la tarea lo antes posible.

Así que puedes llamar a cancelar en la sentencia catch y asegurarte de que nunca se llama a onPostExcute, sino que se invoca a onCancelled en el hilo de la UI. Así puedes mostrar el mensaje de error.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X