2011-08-20 22 views
10

Czy istnieje szczególny sposób na poradzenie sobie z awarią w AsyncTask? O ile mogę powiedzieć, jedynym sposobem jest zwracanie wartości zadania. Chciałbym być w stanie podać więcej szczegółów na temat niepowodzenia, jeśli to możliwe, a wartość null nie jest zbyt obszerna.Jak radzić sobie z awarią AsyncTask

Idealnie byłoby zapewnić obsługę onError, ale nie sądzę, że ma jeden.

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? 
     } 
    }  
} 

Odpowiedz

18

można po prostu zapisać wyjątku w polu i sprawdzić go w onPostExecute() (w celu zapewnienia, że ​​każdy kod błędu obsługi prowadzony jest na wątku UI). Coś jak:

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

Podoba mi się ta odpowiedź, jest bardzo prosta. – leech

+0

dlaczego sprawdzasz wynik zerowy? To się nie może zdarzyć. –

+0

W porządku, ale ten kod został zaadaptowany, oryginał czasami zwraca wartość null. –

2

Co ja zawsze zrobić, to stworzyć nowy obiekt (można to nazwać AsyncTaskResult lub cokolwiek chcesz), które mogą się wrócił z doInBackground. Ten obiekt miałby dwie rzeczy:

  1. Oczekiwany wynik (string w swoim przykładzie)
  2. kod błędu lub nawet jeśli chcesz, sam lub owinięty wersja to obiekt wyjątku. Wszystko, co w zasadzie pomogą obsługi błędu jeśli występuje

Chciałbym następnie powrót ten obiekt do postExecute() i niech ten czek metoda błędu, jeśli jest wtedy poradzić odpowiednio, w przeciwnym razie biorę oczekiwany wynik i rób z nim cokolwiek.

Celem byłoby coś takiego:




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

a kod staje:



    /** 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

Można to zrobić samemu dość łatwo poprzez utworzenie podklasy AsyncTask. Być może coś w stylu ErrorHandlingAsyncTask. Najpierw utwórz abstrakcyjną metodę oddzwaniania onException(Exception e). Twoja metoda doInBackground(Generic... params) powinna zawinąć cały swój kod w bloku try-catch. W bloku catch wywołaj w swoim wyjątku onException(Exception e).

Teraz, gdy potrzebujesz tej funkcji, wystarczy zastąpić nową klasę ErrorHandlingAsyncTask.

Szybki i brudny pseudokod:

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

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

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

nie sądzę, to będzie działać, jeśli chcesz zrobić coś w wątku UI czy istnieje wyjątek rzucony. – dongshengcn

+0

Prawidłowo, będzie to działać w tle. –

5

I zmodyfikowany kod Mikołaja nieco powinna chcesz zrobić coś w wątku UI w wyjątku.

Pamiętaj, że AsyncTask można wykonać tylko raz po utworzeniu instancji.

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

Należy sprawdzić, czy "wyjątek" ma wartość null, a nie "wynik". Ponieważ jeśli 'realDoInBackground' zwróci wartość null, wówczas' onException' zostanie wywołane i przekazane 'null'. – Jamol

0

I połączeniu Momo i odpowiedzi Dongshengcn, a stworzony własną klasę bazową zarówno tła i pierwszego planu wyjątek magazynowe (w przypadku, gdy chcesz zrobić jakąś poważną rejestrowanie błędów)

Chodzi o to, moje kapsułek, kod wszystkie rzeczy i po prostu klasy ResultOrError pozwala przywrócić normalny wynik lub wyjątek

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; 
     } 
    } 
Powiązane problemy