AsyncTask和Android上的error handling

我使用Handler将代码转换为AsyncTask 。 后者非常擅长 – 在主UI线程中asynchronous更新和处理结果。 我不清楚的是,如果在AsyncTask#doInBackground发生exception,如何处理exception。

我这样做的方式是有一个error handling程序并发送消息。 它工作正常,但它是“正确”的方法还是有更好的select?

另外我明白,如果我将error handling程序定义为活动字段,它应该在UI线程中执行。 然而,有时(非常难以预料的),我会得到一个exception说,从Handler#handleMessage触发的代码执行在错误的线程。 我应该在Activity#onCreate初始化error handling程序吗? 将runOnUiThread放入Handler#handleMessage似乎是多余的,但它执行得非常可靠。

它工作正常,但它是“正确”的方法,是否有更好的select?

我坚持在AsyncTask实例本身中的ThrowableException ,然后在onPostExecute()做一些事情,所以我的error handling可以select在屏幕上显示一个对话框。

创build一个AsyncResult对象(您也可以在其他项目中使用)

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

从AsyncTask doInBackground方法返回这个对象,并在postExecute中检查它。 (您可以将此类用作其他asynchronous任务的基类)

以下是从Web服务器获取JSON响应的任务模型。

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

当我觉得需要正确处理AsyncTaskexception时,我使用它作为超类:

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

正常情况下,你可以在你的子类中重写doInBackground来做后台工作,在需要的地方高兴地抛出exception。 然后你被迫执行onPostExecute (因为它是抽象的),这轻轻提醒你处理所有types的Exception ,这是作为parameter passing。 在大多数情况下,exception会导致某种types的UI输出,所以onPostExecute是一个完美的地方。

如果你想使用带来其他好处的RoboGuice框架,你可以尝试RoboAsyncTask,它有一个额外的Callback onException()。 工程真正好,我用它。 http://code.google.com/p/roboguice/wiki/RoboAsyncTask

另一种不依赖于可变成员共享的方式是使用取消。

这是从android文档:

public final boolean cancel(boolean mayInterruptIfRunning)

尝试取消执行此任务。 如果任务已经完成,已经被取消或者由于其他原因不能被取消,则该尝试将失败。 如果成功,并且此任务在调用取消时尚未启动,则此任务不应运行。 如果任务已经开始,那么mayInterruptIfRunning参数确定执行这个任务的线程是否应该被中断以试图停止任务。

调用此方法将导致在doInBackground(Object [])返回后,在UI线程上调用onCancelled(Object)。 调用这个方法可以保证onPostExecute(Object)永远不会被调用。 调用此方法后,应该定期从doInBackground(Object [])中检查isCancelled()返回的值,以尽早完成任务。

所以你可以在catch语句中调用cancel,并确保onPostExcute永远不会被调用,而是在UI线程上调用onCancelled。 所以你可以显示错误信息。

Cagatay Kalan的解决scheme更全面的解决scheme如下所示:

AsyncTaskResult

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

ExceptionHandlingAsyncTask

 public abstract class ExceptionHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, AsyncTaskResult<Result>> { private Context context; public ExceptionHandlingAsyncTask(Context context) { this.context = context; } public Context getContext() { return context; } @Override protected AsyncTaskResult<Result> doInBackground(Params... params) { try { return new AsyncTaskResult<Result>(doInBackground2(params)); } catch (Exception e) { return new AsyncTaskResult<Result>(e); } } @Override protected void onPostExecute(AsyncTaskResult<Result> result) { if (result.getError() != null) { onPostException(result.getError()); } else { onPostExecute2(result.getResult()); } super.onPostExecute(result); } protected abstract Result doInBackground2(Params... params); protected abstract void onPostExecute2(Result result); protected void onPostException(Exception exception) { new AlertDialog.Builder(context).setTitle(R.string.dialog_title_generic_error).setMessage(exception.getMessage()) .setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //Nothing to do } }).show(); } } 

示例任务

 public class ExampleTask extends ExceptionHandlingAsyncTask<String, Void, Result> { private ProgressDialog dialog; public ExampleTask(Context ctx) { super(ctx); dialog = new ProgressDialog(ctx); } @Override protected void onPreExecute() { dialog.setMessage(getResources().getString(R.string.dialog_logging_in)); dialog.show(); } @Override protected Result doInBackground2(String... params) { return new Result(); } @Override protected void onPostExecute2(Result result) { if (dialog.isShowing()) dialog.dismiss(); //handle result } @Override protected void onPostException(Exception exception) { if (dialog.isShowing()) dialog.dismiss(); super.onPostException(exception); } } 

这个简单的课程可以帮助你

 public abstract class ExceptionAsyncTask<Param, Progress, Result, Except extends Throwable> extends AsyncTask<Param, Progress, Result> { private Except thrown; @SuppressWarnings("unchecked") @Override /** * Do not override this method, override doInBackgroundWithException instead */ protected Result doInBackground(Param... params) { Result res = null; try { res = doInBackgroundWithException(params); } catch (Throwable e) { thrown = (Except) e; } return res; } protected abstract Result doInBackgroundWithException(Param... params) throws Except; @Override /** * Don not override this method, override void onPostExecute(Result result, Except exception) instead */ protected void onPostExecute(Result result) { onPostExecute(result, thrown); super.onPostExecute(result); } protected abstract void onPostExecute(Result result, Except exception); } 

我用一个定义callback成功和失败的接口做了我自己的AsyncTask子类。 因此,如果在AsyncTask中引发exception,则onFailure函数将传递该exception,否则,onSuccesscallback会传递您的结果。 为什么android没有更好的东西是超越我的。

 public class SafeAsyncTask<inBackgroundType, progressType, resultType> extends AsyncTask<inBackgroundType, progressType, resultType> { protected Exception cancelledForEx = null; protected SafeAsyncTaskInterface callbackInterface; public interface SafeAsyncTaskInterface <cbInBackgroundType, cbResultType> { public Object backgroundTask(cbInBackgroundType[] params) throws Exception; public void onCancel(cbResultType result); public void onFailure(Exception ex); public void onSuccess(cbResultType result); } @Override protected void onPreExecute() { this.callbackInterface = (SafeAsyncTaskInterface) this; } @Override protected resultType doInBackground(inBackgroundType... params) { try { return (resultType) this.callbackInterface.backgroundTask(params); } catch (Exception ex) { this.cancelledForEx = ex; this.cancel(false); return null; } } @Override protected void onCancelled(resultType result) { if(this.cancelledForEx != null) { this.callbackInterface.onFailure(this.cancelledForEx); } else { this.callbackInterface.onCancel(result); } } @Override protected void onPostExecute(resultType result) { this.callbackInterface.onSuccess(result); } } 

就我个人而言,我会用这种方法。 如果您需要信息,您可以捕捉exception并打印出堆栈跟踪。

让你的任务在后台返回一个布尔值。

就像这样:

  @Override protected Boolean doInBackground(String... params) { return readXmlFromWeb(params[0]); } @Override protected void onPostExecute(Boolean result) { if(result){ // no error } else{ // error handling } } 

另一种可能是将Object用作返回types,并在onPostExecute()检查对象types。 它很短。

 class MyAsyncTask extends AsyncTask<MyInObject, Void, Object> { @Override protected AsyncTaskResult<JSONObject> doInBackground(MyInObject... myInObjects) { try { MyOutObject result; // ... do something that produces the result return result; } catch (Exception e) { return e; } } protected void onPostExecute(AsyncTaskResult<JSONObject> outcome) { if (outcome instanceof MyOutObject) { MyOutObject result = (MyOutObject) outcome; // use the result } else if (outcome instanceof Exception) { Exception e = (Exception) outcome; // show error message } else throw new IllegalStateException(); } } 

如果你知道正确的例外,那么你可以打电话给

 Exception e = null; publishProgress(int ...); 

例如:

 @Override protected Object doInBackground(final String... params) { // TODO Auto-generated method stub try { return mClient.call(params[0], params[1]); } catch(final XMLRPCException e) { // TODO Auto-generated catch block this.e = e; publishProgress(0); return null; } } 

并转到“onProgressUpdate”并执行下列操作

 @Override protected void onProgressUpdate(final Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); mDialog.dismiss(); OptionPane.showMessage(mActivity, "Connection error", e.getMessage()); } 

这只会在某些情况下有所帮助。 您也可以保留一个Global Exceptionvariables并访问exception。