Как работать с ошибкой AsyncTask

Есть ли способ справиться с ошибкой в ​​AsyncTask? Насколько я могу судить, единственный способ – вернуть возвращаемое значение задачи. Я хотел бы иметь возможность предоставить более подробную информацию о сбое, если это возможно, а null – не очень много.

В идеале это обеспечит обработчик onError, но я не думаю, что он есть.

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

Вы можете просто сохранить исключение в поле и проверить его в onPostExecute() (чтобы убедиться, что любой код обработки ошибок запущен в потоке пользовательского интерфейса). Что-то вроде:

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

}

Я немного изменил код Николаса, если вы хотите что-то сделать в потоке пользовательского интерфейса в исключении.

Помните, что AsyncTask можно выполнить только один раз после создания экземпляра.

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

Вы можете сделать это довольно легко, создав подкласс AsyncTask . Возможно, что-то вроде ErrorHandlingAsyncTask . Сначала создайте абстрактный метод обратного вызова onException(Exception e) . Ваш doInBackground(Generic... params) должен обернуть весь его код в блок try-catch . В блоке catch вызовите onException(Exception e) передавая в ваше исключение.

Теперь, когда вам нужна эта функциональность, просто переопределите новый класс ErrorHandlingAsyncTask.

Быстрый и грязный псевдокод:

 class ErrorHandlingAsyncTask extends AsyncTask<..., ..., ...> { protected abstract void onException(Exception e); protected abstract ... realDoInBackground(...); protected ... doInBackground(...) { try { return realDoInBackground(...); } catch(Exception e) { onException(e); } } } 

То, что я всегда делаю, это создать новый объект (вы можете назвать его AsyncTaskResult или как вам нравится), который может быть возвращен с doInBackground. У этого объекта было бы две вещи:

  1. Ожидаемый результат (строка в вашем примере)
  2. Код ошибки или даже если вы хотите, сам объект Exception или его завернутая версия. Все, что в принципе поможет вам справиться с ошибкой, если это произойдет

Затем я вернул бы этот объект в postExecute (), и пусть этот метод проверяет наличие ошибки, если тогда я обрабатываю его соответствующим образом, в противном случае я беру ожидаемый результат и делаю с ним что угодно.

Объект будет примерно таким:

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

И ваш код будет выглядеть следующим образом:

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

Я объединил ответы momo и Dongshengcn и создал свой собственный базовый класс с обработкой исключений фонового и переднего плана (в случае, если вы хотите сделать серьезную регистрацию ошибок)

Дело в том, что мой код инкапсулирует весь материал класса ResultOrError и просто позволяет вам вернуть обычный результат или выбросить исключение

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