【问题标题】:How to handle AsyncTask failure如何处理 AsyncTask 失败
【发布时间】:2012-06-21 12:43:13
【问题描述】:

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

【问题讨论】:

    标签: java android


    【解决方案1】:

    您可以简单地将异常保存在一个字段中并在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();
                }
            }
        }
    

    }

    【讨论】:

    • 我喜欢这个答案,超级简单。
    • 为什么要检查空结果?这不可能发生。
    • 对,但是那个代码被改编了,原来的代码有时会返回 null。
    【解决方案2】:

    我稍微修改了 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;
        }
    }
    

    【讨论】:

    • 您应该检查exception 是否为空而不是result。因为如果realDoInBackground返回null,那么onException会被调用并传递null
    【解决方案3】:

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

    【讨论】:

    • 如果你想在 UI 线程中做一些事情,如果抛出异常,不要认为这会起作用。
    • 正确,这将在后台运行。
    【解决方案4】:

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

    1. 预期结果(示例中为字符串)
    2. 错误代码,或者即使您需要,也可以是异常对象本身或其包装版本。如果发生任何错误,基本上可以帮助您处理错误

    然后我会将此对象返回给 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
            }
        }
    
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-09-23
        • 2010-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-22
        • 1970-01-01
        相关资源
        最近更新 更多