捕获AsyncTask的异常。需要思考

时间:2012-06-08 07:06:59

标签: android exception-handling

我想在doInBackground中捕获线程的异常并在onPostExcecute中打印错误消息。问题是我在onPostExecute中没有Throwable对象。如何在非UI线程中捕获异常在UI线程中打印错误消息

public class TestTask extends AsyncTask<Void, Void, List<String>> {

    @Override
    protected List<String> doInBackground(final Void... params) {
        try {
            ...
            return listOfString;
        } catch(SomeCustomException e) {
            ...
            return null;
        }       
    }

    @Override
    protected void onPostExecute(final List<String> result) {
        if(result == null) {
            // print the error of the Throwable "e".
            // The problem is I don't have the Throwable object here! So I can't check the type of exception.
        }

    }
}

Arun回答后更新:

这是我的AsyncTask包装类。它打算在doInBackground中处理异常,但我找不到一个好的解决方案。

public abstract class AbstractWorkerTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result>
implements Workable {
    protected OnPreExecuteListener onPreExecuteListener;
    protected OnPostExecuteListener<Result> onPostExecuteListener;
    protected ExceptionHappenedListener exceptionHappendedListener;
    private boolean working;

    @Override
    protected void onPreExecute() {
        if (onPreExecuteListener != null) {
            onPreExecuteListener.onPreExecute();
        }
        working = true;
    }

    @Override
    protected void onPostExecute(final Result result) {
        working = false;
        if(/* .........*/ ) {
            exceptionHappendedListener.exceptionHappended(e);
        }
        if (onPostExecuteListener != null) {
            onPostExecuteListener.onPostExecute(result);
        }
    }

    @Override
    public boolean isWorking() {
        return working;
    }

    public void setOnPreExecuteListener(final OnPreExecuteListener onPreExecuteListener) {
        this.onPreExecuteListener = onPreExecuteListener;
    }

    public void setOnPostExecuteListener(final OnPostExecuteListener<Result> onPostExecuteListener) {
        this.onPostExecuteListener = onPostExecuteListener;
    }

    public void setExceptionHappendedListener(final ExceptionHappenedListener exceptionHappendedListener) {
        this.exceptionHappendedListener = exceptionHappendedListener;
    }

    public interface OnPreExecuteListener {
        void onPreExecute();
    }

    public interface OnPostExecuteListener<Result> {
        void onPostExecute(final Result result);
    }

    public interface ExceptionHappenedListener {
        void exceptionHappended(Exception e);
    }
}

3 个答案:

答案 0 :(得分:7)

doInBackground()的返回类型更改为Object,当您在onPostExecute(Object result)收到结果时,请使用instanceOf运算符检查返回的结果是否为{{1 }或Exception

修改

由于结果可以是Exception,也可以是正确的List,您可以使用以下命令:

List<String>

同时更改以下声明:

protected void onPostExecute(final Object result) {
    working = false;
    if(result instanceof SomeCustomException) {
        exceptionHappendedListener.exceptionHappended(result);
    }
    else{
        if (onPostExecuteListener != null) {
            onPostExecuteListener.onPostExecute(result);
        }
    }
}

答案 1 :(得分:4)

只需将Exception存储到列表中并稍后处理,因为onPostExecute()总是在doInBackground()之后调用:

public class TestTask extends AsyncTask<Params, Progress, Result> {

  List<Exception> exceptions = new ArrayList<Exception>();

  @Override
  protected Result doInBackground(Params... params) {
    try {
      ...
    } catch(SomeCustomException e) {
      exceptions.add(e);
    }
    return result;
  }

  @Override
  protected void onPostExecute(Result result) {
    for (Exception e : exceptions) {
      // Do whatever you want for the exception here
      ...
    }
  }

}

这是可行但很少使用,因为在大多数情况下,我们希望一旦被抛出并捕获就处理异常:

public class TestTask extends AsyncTask<Params, Progress, Result> {

  @Override
  protected Result doInBackground(Params... params) {
    try {
      ...
    } catch(SomeCustomException e) {
      // If you need update UI, simply do this:
      runOnUiThread(new Runnable() {
        public void run() {
          // update your UI component here.
          myTextView.setText("Exception!!!");
        }
      });
    }
    return result;
  }

}

希望这是有道理的。

答案 2 :(得分:4)

doInBackground的返回类型更改为Object可能会传递Exception,然后使用instanceof()是代码异味的来源(糟糕的编程习惯)。最好将返回类型限制为您想要返回的特定内容。

根据此answer,只需添加一个私有成员来存储doInBackground中抛出的异常,然后在onPostExecute中首先检查它。

只需要捕获一个Exception因为您应该在抛出异常后立即停止doInBackground中的操作,并在onPostExecute中正常处理它,您可以访问UI元素和所以可以告知用户不幸事故。

通用示例(AsyncTask的主体):

private Exception mException

@Override
protected Result doInBackground(Params... params) {
    try {
          // --- Do something --- //
    }
    catch( SomeException e ){ mException = e; return null; }
}

@Override
protected void onPostExecute(Result result) {
    if (mException != null) {
        // --- handle exception --- //
        return;
    }

    // --- Perform normal post execution actions --- //
}