如何处理AsyncTask失败

时间:2011-08-20 16:14:20

标签: java android

是否有一种特定的方法来处理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?
        }
    }       
}

5 个答案:

答案 0 :(得分:18)

您可以简单地将异常保存在字段中并在onPostExecute()中进行检查(以确保在UI线程上运行任何错误处理代码)。类似的东西:

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

}

答案 1 :(得分:5)

我修改了Nicholas的代码,如果你想在异常的UI线程中做一些事情。

请记住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;
    }
}

答案 2 :(得分:2)

我一直在做的是创建一个可以通过doInBackground返回的新对象(可以称之为AsyncTaskResult或任何你喜欢的)。这个对象有两件事:

  1. 预期结果(示例中的字符串)
  2. 错误代码,甚至是你想要的,Exception对象本身或它的包装版本。任何基本上可以帮助你处理错误的事情
  3. 然后我将这个对象返回到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
            }
        }
    
    

答案 3 :(得分:2)

您可以通过创建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);
        }
    }
}

答案 4 :(得分:0)

我结合了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;
        }
    }