简体   繁体   English

如何处理AsyncTask失败

[英]How to handle AsyncTask failure

Is there a specific way to handle failure in an AsyncTask? 是否有一种特定的方法来处理AsyncTask中的故障? As far as I can tell the only way is with the return value of task. 据我所知,唯一的方法是使用任务的返回值。 I'd like to be able to provide more details on the failure if possible, and null isn't very verbose. 如果可能的话,我希望能够提供有关失败的更多细节,并且null不是很冗长。

Ideally it would provide an onError handler, but I don't think it has one. 理想情况下它会提供一个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?
        }
    }       
}

You can simply save the exception in a field and check it in onPostExecute() (to ensure that any error handling code is run on the UI thread). 您可以简单地将异常保存在字段中并在onPostExecute()检查(以确保在UI线程上运行任何错误处理代码)。 Something like: 就像是:

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

} }

I modified Nicholas's code a bit, should you want to do something in the UI thread in exception. 我修改了Nicholas的代码,如果你想在异常的UI线程中做一些事情。

Remember the AsyncTask can only be executed once after instantiated. 请记住,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;
    }
}

What I always do is create a new Object (you can call it AsyncTaskResult or whatever you like) that can get returned with doInBackground. 我一直在做的是创建一个新的Object(你可以称之为AsyncTaskResult或任何你喜欢的东西),它可以通过doInBackground返回。 This Object would have two things: 这个对象有两件事:

  1. The expected result (String in your example) 预期结果(示例中的字符串)
  2. Error code or even if you want, the Exception object itself or a wrapped version of it. 错误代码,甚至是你想要的,Exception对象本身或它的包装版本。 Anything that basically will help you handling error if any occurs 任何基本上可以帮助您处理错误的事情

I would then return this object to postExecute() and let that method check for the error, if there is then I handle it accordingly, otherwise I take the expected result and do whatever with it. 然后我会将此对象返回到postExecute()并让该方法检查错误,如果有,那么我会相应地处理它,否则我采取预期的结果并对它做任何事情。

The object would be something like: 对象将是这样的:




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

And your code becomes : 你的代码变成了:



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

You can do this yourself pretty easily by creating a subclass of AsyncTask . 您可以通过创建AsyncTask的子类来轻松地自己完成此AsyncTask Perhaps something like ErrorHandlingAsyncTask . 也许像ErrorHandlingAsyncTask东西。 First create an abstract callback method onException(Exception e) . 首先在onException(Exception e)创建一个抽象回调方法。 Your doInBackground(Generic... params) method should wrap all of its code in a try-catch block. 您的doInBackground(Generic... params)方法应将其所有代码包装在try-catch块中。 In the catch block, call out to onException(Exception e) passing in your exception. catch块中,调用传递onException(Exception e)

Now, when you need this functionality, just override your new ErrorHandlingAsyncTask class. 现在,当您需要此功能时,只需覆盖新的ErrorHandlingAsyncTask类。

Quick and dirty pseudo code: 快速而脏的伪代码:

class ErrorHandlingAsyncTask extends AsyncTask<..., ..., ...> {
    protected abstract void onException(Exception e);

    protected abstract ... realDoInBackground(...);

    protected ... doInBackground(...) {
        try {
            return realDoInBackground(...);
        } catch(Exception e) {
            onException(e);
        }
    }
}

I combined momo's and Dongshengcn's answers, and created my own base class with both background and foreground exception handling (in case you want to do some serious error logging) 我结合了momo和Dongshengcn的答案,并创建了我自己的基类,同时具有后台和前台异常处理(如果你想做一些严重的错误记录)

The thing is, my code encapsulates all of the ResultOrError class stuff and simply lets you return the normal result or throw an exception 问题是,我的代码封装了所有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;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM