The AsyncTask
available in android, gives you the result from doInBackground
on the UI thread so that you can update UI according to the result, but exceptions need to be handled inside doInBackground
function.
So following is my generic solution to the problem, the main objective here is to allow user to handle exceptions exactly the same way he does when working with synchronous code.
public abstract class AsyncTaskWithThrowable<Params, Progress, Result> {
public class ResultHolder<Result> {
private ResultHolder(Result result) {
_result = result;
}
private ResultHolder(Throwable throwable) {
_throwable = throwable;
}
private Throwable _throwable = null;
private Result _result;
public Result getResult() throws Throwable{
if (_throwable != null) {
throw _throwable;
}
return _result;
}
}
private AsyncTask<Params, Progress, ResultHolder<Result>> _asyncTask = new AsyncTask<Params, Progress, ResultHolder<Result>>() {
@Override
protected ResultHolder<Result> doInBackground(Params... params) {
try {
return new ResultHolder<Result>(AsyncTaskWithThrowable.this.doInBackground(params));
}
catch (Throwable e) {
new ResultHolder<Result>(e);
return null;
}
}
@Override
protected void onPreExecute() {
AsyncTaskWithThrowable.this.onPreExecute();
}
@Override
protected void onPostExecute(ResultHolder<Result> result) {
AsyncTaskWithThrowable.this.onPostExecute(result);
}
@Override
protected void onProgressUpdate(Progress... values) {
AsyncTaskWithThrowable.this.onProgressUpdate(values);
}
};
public abstract Result doInBackground(Params ... params) throws Throwable;
protected void onPreExecute() {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onPostExecute(ResultHolder<Result> resultHolder) {
}
@SuppressWarnings({"UnusedDeclaration"})
protected void onProgressUpdate(Progress... values) {
}
public final AsyncTaskWithThrowable<Params, Progress, Result> execute(Params... params) {
_asyncTask.execute(params);
return this;
}
}
And this is how you use it.
new AsyncTaskWithThrowable<Boolean, Void, String>(){
@Override
protected String doInBackground(Boolean ...params) {
if (!params[0]) {
throw new InvalidParameterException();
}
return "result";
}
@Override
protected void onPostExecute(ResultHolder<String> resultHolder) {
try{
String result = resultHolder.getResult();
// Change UI
}
catch (InvalidParameterException e) {
// Change UI
}
catch (Throwable e) {
// I don't like this catch block, but i couldn't find a way to avoid it.
}
}
}.execute(false);
The problem I see with it is user is forced to handle Throwable
(also doInBackground
can throw anything), but I cannot use typed parameter for exception here, as Java doesn't allow to catch it.