AsyncTask and error handling on Android

前端 未结 12 2109
失恋的感觉
失恋的感觉 2020-11-27 10:32

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

相关标签:
12条回答
  • 2020-11-27 10:48

    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();
        }
    
    0 讨论(0)
  • 2020-11-27 10:50

    Another way that doesn't depend on variable member sharing is to use cancel.

    This is from android docs:

    public final boolean cancel (boolean mayInterruptIfRunning)

    Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

    Calling this method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked. After invoking this method, you should check the value returned by isCancelled() periodically from doInBackground(Object[]) to finish the task as early as possible.

    So you can call cancel in catch statement and be sure that onPostExcute is never called, but instead onCancelled is invoked on UI thread. So you can show the error message.

    0 讨论(0)
  • 2020-11-27 10:50

    Another possibility would be to use Object as return type, and in onPostExecute() check for the object type. It is short.

    class MyAsyncTask extends AsyncTask<MyInObject, Void, Object> {
    
        @Override
        protected AsyncTaskResult<JSONObject> doInBackground(MyInObject... myInObjects) {
            try {
                MyOutObject result;
                // ... do something that produces the result
                return result;
            } catch (Exception e) {
                return e;
            }
        }
    
        protected void onPostExecute(AsyncTaskResult<JSONObject> outcome) {
            if (outcome instanceof MyOutObject) {
                MyOutObject result = (MyOutObject) outcome;
                // use the result
            } else if (outcome instanceof Exception) {
                Exception e = (Exception) outcome;
                // show error message
            } else throw new IllegalStateException();
        }
    }
    
    0 讨论(0)
  • 2020-11-27 10:50

    If you know the correct exception then you can call the

    Exception e = null;
    
    publishProgress(int ...);
    

    eg:

    @Override
    protected Object doInBackground(final String... params) {
    
        // TODO Auto-generated method stub
        try {
            return mClient.call(params[0], params[1]);
        } catch(final XMLRPCException e) {
    
            // TODO Auto-generated catch block
            this.e = e;
            publishProgress(0);
            return null;
        }
    }
    

    and go to "onProgressUpdate" and do the folowing

    @Override
    protected void onProgressUpdate(final Integer... values) {
    
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);
        mDialog.dismiss();
        OptionPane.showMessage(mActivity, "Connection error", e.getMessage());
    }
    

    This will be helpful in some cases only. Also you can keep a Global Exception variable and access the exception.

    0 讨论(0)
  • 2020-11-27 10:57

    When I feel the need to handle Exceptions in AsyncTask properly, I use this as super class:

    public abstract class ExceptionAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
    
        private Exception exception=null;
        private Params[] params;
    
        @Override
        final protected Result doInBackground(Params... params) {
            try {
                this.params = params; 
                return doInBackground();
            }
            catch (Exception e) {
                exception = e;
                return null;
            }
        }
    
        abstract protected Result doInBackground() throws Exception;
    
        @Override
        final protected void onPostExecute(Result result) {
            super.onPostExecute(result);
            onPostExecute(exception, result);
        }
    
        abstract protected void onPostExecute(Exception exception, Result result);
    
        public Params[] getParams() {
            return params;
        }
    
    }
    

    As normal, you override doInBackground in your subclass to do background work, happily throwing Exceptions where needed. You are then forced to implement onPostExecute (because it's abstract) and this gently reminds you to handle all types of Exception, which are passed as parameter. In most cases, Exceptions lead to some type of ui output, so onPostExecute is a perfect place to do that.

    0 讨论(0)
  • 2020-11-27 11:01

    Create an AsyncResult object ( which you can also use in other projects)

    public class AsyncTaskResult<T> {
        private T result;
        private Exception error;
    
        public T getResult() {
            return result;
        }
    
        public Exception getError() {
            return error;
        }
    
        public AsyncTaskResult(T result) {
            super();
            this.result = result;
        }
    
        public AsyncTaskResult(Exception error) {
            super();
            this.error = error;
        }
    }
    

    Return this object from your AsyncTask doInBackground methods and check it in the postExecute. ( You can use this class as a base class for your other async tasks )

    Below is a mockup of a task that gets a JSON response from the web server.

    AsyncTask<Object,String,AsyncTaskResult<JSONObject>> jsonLoader = new AsyncTask<Object, String, AsyncTaskResult<JSONObject>>() {
    
            @Override
            protected AsyncTaskResult<JSONObject> doInBackground(
                    Object... params) {
                try {
                    // get your JSONObject from the server
                    return new AsyncTaskResult<JSONObject>(your json object);
                } catch ( Exception anyError) {
                    return new AsyncTaskResult<JSONObject>(anyError);
                }
            }
    
            protected void onPostExecute(AsyncTaskResult<JSONObject> result) {
                if ( result.getError() != null ) {
                    // error handling here
                }  else if ( isCancelled()) {
                    // cancel handling here
                } else {
    
                    JSONObject realResult = result.getResult();
                    // result handling here
                }
            };
    
        }
    
    0 讨论(0)
提交回复
热议问题