2011-08-20 6 views
10

¿Hay alguna manera específica de manejar fallas en una AsyncTask? Por lo que puedo decir, la única forma es con el valor de retorno de la tarea. Me gustaría poder proporcionar más detalles sobre el error si es posible, y null no es muy detallado.Cómo manejar la falla de AsyncTask

Lo ideal sería proporcionar un controlador onError, pero no creo que tenga uno.

class DownloadAsyncTask extends AsyncTask<String, Void, String> { 

    /** this would be cool if it existed */ 
    @Override 
    protected void onError(Exception ex) { 
     ... 
    } 

    @Override 
    protected String doInBackground(String... params) { 
    try { 
      ... download ... 
     } catch (IOException e) { 
      setError(e); // maybe like this? 
     } 
    }  
} 

Respuesta

18

Usted puede simplemente guardar la excepción en un campo y comprobar que en onPostExecute() (para asegurar que ningún código de control de errores se ejecuta en el subproceso de interfaz de usuario). Algo así como:

new AsyncTask<Void, Void, Boolean>() { 
    Exception error; 

    @Override 
    protected Boolean doInBackground(Void... params) { 
     try { 
      // do work 
      return true; 
     } catch (Exception e) { 
      error = e; 

      return false; 
     } 
    } 

    @Override 
    protected void onPostExecute(Boolean result) { 
     if (result) { 
      Toast.makeText(ctx, "Success!", 
       Toast.LENGTH_SHORT).show(); 
     } else { 
      if (error != null) { 
       Toast.makeText(ctx, error.getMessage(), 
         Toast.LENGTH_SHORT).show(); 
      } 
     } 
    } 

}

+0

Me gusta esta respuesta, es súper simple. – leech

+0

¿por qué está buscando un resultado nulo? No puede suceder –

+0

Derecha, pero ese código fue adaptado, el original devuelve nulo a veces. –

2

lo que siempre hago es crear un nuevo objeto (se le puede llamar AsyncTaskResult o lo que quieras) que pueden quedar vuelto con doInBackground. Este objeto tendría dos cosas:

  1. El resultado esperado (String en el ejemplo)
  2. código de error o incluso si lo desea, la propia o una versión envuelta de ella objeto de excepción. Cualquier cosa que básicamente le ayude a manejar el error si ocurre

Devolvería este objeto a postExecute() y dejaría que ese método verificara el error, si es que entonces lo manejo en consecuencia, de lo contrario, tomo el esperado resultado y hacer lo que sea con él.

El objeto sería algo así como:




    public class AsyncTaskResult<T extends Object> { 
      Exception exception; 
      T asyncTaskResult; 

      public void setResult(T asyncTaskResult) { 
       this.asyncTaskResult = asyncTaskResult; 
      } 

      public T getResult() { 
       return asyncTaskResult; 
      } 

      public void setException(Exception exception) { 
       this.exception = exception; 
      } 

      public boolean hasException() { 
       return exception != null; 
      } 

      public Exception getException() { 
       return exception; 
      } 
     } 

y su código se convierte en:



    /** this would be cool if it existed */ 
    protected void onError(Exception ex) { 
     // handle error... 
    } 

    @Override 
    protected AsyncTaskResult<String> doInBackground(String... params) { 
     AsyncTaskResult<String> result = new AsyncTaskResult<String>(); 
     try { 
      // ... download ... 
     } catch (IOException e) { 
      result.setException(e); 
     } 

     return result; 
    }  

    @Override 
    protected void onPostExecute(AsyncTaskResult<String> result) { 
     if(result.hasException()) { 
      // handle error here... 
      onError(result.getException()); 
     } else { 
      // deal with the result 
     } 
    } 

2

Puede hacerlo usted mismo con bastante facilidad mediante la creación de una subclase de AsyncTask. Tal vez algo así como ErrorHandlingAsyncTask. Primero crea un método de devolución de llamada abstracto onException(Exception e). Su método doInBackground(Generic... params) debe ajustar todo su código en un bloque try-catch. En el bloque catch, llame al onException(Exception e) pasando su excepción.

Ahora, cuando necesite esta funcionalidad, solo anule su nueva clase ErrorHandlingAsyncTask.

rápida y sucia pseudo código:

class ErrorHandlingAsyncTask extends AsyncTask<..., ..., ...> { 
    protected abstract void onException(Exception e); 

    protected abstract ... realDoInBackground(...); 

    protected ... doInBackground(...) { 
     try { 
      return realDoInBackground(...); 
     } catch(Exception e) { 
      onException(e); 
     } 
    } 
} 
+0

no creo que esto va a funcionar si usted quiere hacer algo en el hilo de interfaz de usuario si hay excepción lanzada. – dongshengcn

+0

Correcto, esto se ejecutará en segundo plano. –

5

que modifica el código de Nicholas un poco, en caso de que desee hacer algo en el hilo de interfaz de usuario en la excepción.

Recuerde que AsyncTask solo se puede ejecutar una vez después de la instancia.

class ErrorHandlingAsyncTask extends AsyncTask<..., ..., ...> { 

    private Exception exception = null; 

    protected abstract void onResult(Result result); 

    protected abstract void onException(Exception e); 

    protected abstract ... realDoInBackground(...); 

    @Override 
    final protected void onPostExecute(Result result) { 
     if(result != null) { 
      onResult(result); 
     } else { 
      onException(exception); 
     } 
    } 

    @Override 
    protected ... doInBackground(...) { 
     try { 
      return realDoInBackground(...); 
     } catch(Exception e) { 
      exception = e; 
     } 
     return null; 
    } 
} 
+0

Debe comprobar si 'exception' es nulo en lugar de' result'. Porque si 'realDoInBackground' devuelve null, se llamará a' onException' y se pasará a 'null'. – Jamol

0

he combinado de momo y respuestas de Dongshengcn, y creé mi propia clase base con el fondo y excepción primer plano manipulación (en caso de que quiera hacer algún registro de errores graves)

La cosa es que mis encapsulados de código todas las cosas clase ResultOrError y simplemente le permite devolver el resultado normal o lanzar una excepción

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

    /** 
    * Wraps the calling of the {@link #doTask(Object[])} method, also handling 
    * the exceptions possibly thrown. 
    */ 
    protected final ResultOrException<Result> doInBackground(Params... params) { 
     try { 
      Result res = doTask(params); 
      return new ResultOrException<Result>(res); 
     } catch (Exception e) { 
      onBackgroundException(e); 
      return new ResultOrException<Result>(e); 
     } 
    } 

    /** 
    * Override this method to perform a computation on a background thread. The 
    * specified parameters are the parameters passed to 
    * {@link #doTask(Object[])} by the caller of this task. This method can 
    * call {@link #publishProgress(Object...)} to publish updates on the UI 
    * thread. 
    * 
    * @param params 
    *   The parameters of the task. 
    * @return A result, defined by the subclass of this task. 
    */ 
    protected abstract Result doTask(Params[] params); 

    /** 
    * Handles calling the {@link #onSuccess(Object)} and 
    * {@link #onFailure(Exception)} methods. 
    */ 
    @Override 
    protected final void onPostExecute(ResultOrException<Result> result) { 
     if (result.getException() != null) { 
      onFailure(result.getException()); 
     } else { 
      onSuccess(result.getResult()); 
     } 
    } 

    /** 
    * Called when an exception was thrown in {@link #doTask(Object[])}. Handled 
    * in the background thread. 
    * 
    * @param exception 
    *   The thrown exception 
    */ 
    protected void onBackgroundException(Exception exception) { 
    } 

    /** 
    * Called when the {@link #doTask(Object[])} method finished executing with 
    * no exceptions thrown. 
    * 
    * @param result 
    *   The result returned from {@link #doTask(Object[])} 
    */ 
    protected void onSuccess(Result result) { 
    } 

    /** 
    * Called when an exception was thrown in {@link #doTask(Object[])}. Handled 
    * in the foreground thread. 
    * 
    * @param exception 
    *   The thrown exception 
    */ 
    protected void onFailure(Exception exception) { 
    } 
} 

class ResultOrException<TResult> { 

    /** 
    * The possibly thrown exception 
    */ 
    Exception mException; 

    /** 
    * The result, if no exception was thrown 
    */ 
    TResult  mResult; 

    /** 
    * @param exception 
    *   The thrown exception 
    */ 
    public ResultOrException(Exception exception) { 
     mException = exception; 
    } 

    /** 
    * @param result 
    *   The result returned from the method 
    */ 
    public ResultOrException(TResult result) { 
     mResult = result; 
    } 

    /** 
    * @return the exception 
    */ 
    public Exception getException() { 
     return mException; 
    } 

    /** 
    * @param exception 
    *   the exception to set 
    */ 
    public void setException(Exception exception) { 
     mException = exception; 
    } 

    /** 
    * @return the result 
    */ 
    public TResult getResult() { 
     return mResult; 
    } 

    /** 
    * @param result 
    *   the result to set 
    */ 
     public void setResult(TResult result) { 
      mResult = result; 
     } 
    } 
Cuestiones relacionadas