AsyncTask and error handling on Android

Viewed 75519

I'm converting my code from using Handler to AsyncTask. The latter is great at what it does - asynchronous updates and handling of results in the main UI thread. What's unclear to me is how to handle exceptions if something goes haywire in AsyncTask#doInBackground.

The way I do it is to have an error Handler and send messages to it. It works fine, but is it the "right" approach or is there better alternative?

Also I understand that if I define the error Handler as an Activity field, it should execute in the UI thread. However, sometimes (very unpredictably) I will get an Exception saying that code triggered from Handler#handleMessage is executing on the wrong thread. Should I initialize error Handler in Activity#onCreate instead? Placing runOnUiThread into Handler#handleMessage seems redundant but it executes very reliably.

12 Answers

Actually, AsyncTask use FutureTask & Executor, FutureTask support exception-chain

First let's define a helper class

public static class AsyncFutureTask<T> extends FutureTask<T> {

    public AsyncFutureTask(@NonNull Callable<T> callable) {
        super(callable);
    }

    public AsyncFutureTask<T> execute(@NonNull Executor executor) {
        executor.execute(this);
        return this;
    }

    public AsyncFutureTask<T> execute() {
        return execute(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    @Override
    protected void done() {
        super.done();
        //work done, complete or abort or any exception happen
    }
}

Second, let's use

    try {
        Log.d(TAG, new AsyncFutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //throw Exception in worker thread
                throw new Exception("TEST");
            }
        }).execute().get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        //catch the exception throw by worker thread in main thread
        e.printStackTrace();
    }

or use FutureTask directly like below

    FutureTask<?> futureTask = new FutureTask(() -> {throw new RuntimeException("Exception in TaskRunnable");}) {
        @Override
        protected void done() {
            super.done();
            //do something
            Log.d(TAG,"FutureTask done");
        }
    };

    AsyncTask.THREAD_POOL_EXECUTOR.execute(futureTask);

    try {
        futureTask.get();
    } catch (ExecutionException | InterruptedException e) {
        Log.d(TAG, "Detect exception in futureTask", e);
    }

logcat as below enter image description here

Personally, I will use this approach. You can just catch the exceptions and print out the stack trace if you need the info.

make your task in background return a boolean value.

it's like this:

    @Override
                protected Boolean doInBackground(String... params) {
                    return readXmlFromWeb(params[0]);
         }

        @Override
                protected void onPostExecute(Boolean result) {

              if(result){
              // no error
               }
              else{
                // error handling
               }
}
Related