Вопрос

Я преобразую свой код с использования Handler к AsyncTask. Анкет Последний отлично подходит в том, что он делает - асинхронные обновления и обработку результатов в основной потоке пользовательского интерфейса. Что неясно для меня, так это то, как справиться с исключениями, если что -то не склоняется к AsyncTask#doInBackground.

То, как я это делаю, состоит в том, чтобы иметь обработчик ошибок и отправлять ему сообщения. Он работает нормально, но это «правильный» подход или есть лучшая альтернатива?

Также я понимаю, что если я определю обработчик ошибок как поле активности, он должен выполнять в потоке пользовательского интерфейса. Однако иногда (очень непредсказуемо) я получу исключение, говоря, что код запускается из Handler#handleMessage Выполняет не в неправильном потоке. Должен ли я инициализировать обработчик ошибок в Activity#onCreate вместо? Размещение runOnUiThread в Handler#handleMessage кажется излишним, но он очень надежно выполняется.

Это было полезно?

Решение

Он работает нормально, но это «правильный» подход, и есть ли лучшая альтернатива?

Я держусь за Throwable или же Exception в AsyncTask сам экземпляр, а затем сделай что -нибудь с ним в onPostExecute(), поэтому моя обработка ошибок имеет возможность отобразить диалог на экране.

Другие советы

Создайте объект Asyncresult (который вы также можете использовать в других проектах)

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

Верните этот объект из ваших методов Asynctask Doinbackground и проверьте его в постксекте. (Вы можете использовать этот класс в качестве базового класса для других ваших асинхронных задач)

Ниже приведен макет задачи, которая получает ответ JSON от веб -сервера.

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

    }

Когда я чувствую необходимость справиться с исключениями в AsyncTask Правильно, я использую это как супер класс:

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

}

Как обычно, вы переопределяете doInBackground В вашем подклассе, чтобы выполнять фоновую работу, с радостью бросает исключения, где это необходимо. Затем вы вынуждены реализовать onPostExecute (Потому что это абстрактно), и это мягко напоминает вам о том, чтобы справиться со всеми типами Exception, которые передаются как параметр. В большинстве случаев исключения приводят к некоторому типу вывода пользовательского интерфейса, поэтому onPostExecute это идеальное место, чтобы сделать это.

Если вы хотите использовать Roboguice Framework, которая приносит вам другие преимущества, вы можете попробовать Roboasynctask, которая имеет дополнительный обратный обратный ход Onexception (). Работает очень хорошо, и я использую это.http://code.google.com/p/roboguice/wiki/roboasynctask

Я сделал свой собственный подкласс Asynctask с интерфейсом, который определяет обратные вызовы для успеха и неудачи. Таким образом, если исключение добавлено в вашу Asynctask, функция Onfailure передается исключением, в противном случае обратный вызов Onsuccess проходит ваш результат. Почему у Android нет чего -то лучшего доступного мне.

public class SafeAsyncTask<inBackgroundType, progressType, resultType>
extends AsyncTask<inBackgroundType, progressType, resultType>  {
    protected Exception cancelledForEx = null;
    protected SafeAsyncTaskInterface callbackInterface;

    public interface SafeAsyncTaskInterface <cbInBackgroundType, cbResultType> {
        public Object backgroundTask(cbInBackgroundType[] params) throws Exception;
        public void onCancel(cbResultType result);
        public void onFailure(Exception ex);
        public void onSuccess(cbResultType result);
    }

    @Override
    protected void onPreExecute() {
        this.callbackInterface = (SafeAsyncTaskInterface) this;
    }

    @Override
    protected resultType doInBackground(inBackgroundType... params) {
        try {
            return (resultType) this.callbackInterface.backgroundTask(params);
        } catch (Exception ex) {
            this.cancelledForEx = ex;
            this.cancel(false);
            return null;
        }
    }

    @Override
    protected void onCancelled(resultType result) {
        if(this.cancelledForEx != null) {
            this.callbackInterface.onFailure(this.cancelledForEx);
        } else {
            this.callbackInterface.onCancel(result);
        }
    }

    @Override
    protected void onPostExecute(resultType result) {
        this.callbackInterface.onSuccess(result);
    }
}

Более полное решение для CAGATAY KALANРешение показано ниже:

Asynctaskresult

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

ExceptionHandlingAsynctask

public abstract class ExceptionHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, AsyncTaskResult<Result>>
{
    private Context context;

    public ExceptionHandlingAsyncTask(Context context)
    {
        this.context = context;
    }

    public Context getContext()
    {
        return context;
    }

    @Override
    protected AsyncTaskResult<Result> doInBackground(Params... params)
    {
        try
        {
            return new AsyncTaskResult<Result>(doInBackground2(params));
        }
        catch (Exception e)
        {
            return new AsyncTaskResult<Result>(e);
        }
    }

    @Override
    protected void onPostExecute(AsyncTaskResult<Result> result)
    {
        if (result.getError() != null)
        {
            onPostException(result.getError());
        }
        else
        {
            onPostExecute2(result.getResult());
        }
        super.onPostExecute(result);
    }

    protected abstract Result doInBackground2(Params... params);

    protected abstract void onPostExecute2(Result result);

    protected void onPostException(Exception exception)
    {
                        new AlertDialog.Builder(context).setTitle(R.string.dialog_title_generic_error).setMessage(exception.getMessage())
                .setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener()
                {
                    public void onClick(DialogInterface dialog, int which)
                    {
                        //Nothing to do
                    }
                }).show();
    }
}

Пример задания

public class ExampleTask extends ExceptionHandlingAsyncTask<String, Void, Result>
{
    private ProgressDialog  dialog;

    public ExampleTask(Context ctx)
    {
        super(ctx);
        dialog = new ProgressDialog(ctx);
    }

    @Override
    protected void onPreExecute()
    {
        dialog.setMessage(getResources().getString(R.string.dialog_logging_in));
        dialog.show();
    }

    @Override
    protected Result doInBackground2(String... params)
    {
        return new Result();
    }

    @Override
    protected void onPostExecute2(Result result)
    {
        if (dialog.isShowing())
            dialog.dismiss();
        //handle result
    }

    @Override
    protected void onPostException(Exception exception)
    {
        if (dialog.isShowing())
            dialog.dismiss();
        super.onPostException(exception);
    }
}

Этот простой класс может помочь вам

public abstract class ExceptionAsyncTask<Param, Progress, Result, Except extends Throwable> extends AsyncTask<Param, Progress, Result> {
    private Except thrown;

    @SuppressWarnings("unchecked")
    @Override
    /**
     * Do not override this method, override doInBackgroundWithException instead
     */
    protected Result doInBackground(Param... params) {
        Result res = null;
        try {
            res = doInBackgroundWithException(params);
        } catch (Throwable e) {
            thrown = (Except) e;
        }
        return res;
    }

    protected abstract Result doInBackgroundWithException(Param... params) throws Except;

    @Override
    /**
     * Don not override this method, override void onPostExecute(Result result, Except exception) instead
     */
    protected void onPostExecute(Result result) {
        onPostExecute(result, thrown);
        super.onPostExecute(result);
    }

    protected abstract void onPostExecute(Result result, Except exception);
}

Другим способом, который не зависит от совместного использования членов переменной, является использование отмены.

Это от Android Docs:

Общественная финальная логическая отмена (Boolean Mayintertifrunning)

Попытки отменить выполнение этой задачи. Эта попытка потерпит неудачу, если задача уже выполнена, уже была отменена или не может быть отменена по какой -либо другой причине. В случае успеха, и эта задача не началась при вызове Cancel, эта задача никогда не должна работать. Если задача уже началась, то параметр MayIntertifrunning определяет, следует ли прервать поток, выполняющий эту задачу в попытке остановить задачу.

Призыв этого метода приведет к тому, что онкан (объект) будет вызван в потоке пользовательского интерфейса после возврата doinbackground (Object []). Призыв этого метода гарантирует, что OnPostexecute (Object) никогда не вызывается. После вызова этого метода вы должны проверять значение, возвращаемое ISCancelled () периодически от Doinbackground (Object []), чтобы завершить задачу как можно раньше.

Таким образом, вы можете позвонить в оператор CANCE и убедиться, что OnPostExcute никогда не называется, но вместо этого в потоке пользовательского интерфейса используется. Таким образом, вы можете показать сообщение об ошибке.

На самом деле, Asynctask Используйте FutureTask & Executor, FutureTask Support Checain Сначала давайте определим вспомогательный класс

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

Во -вторых, давайте использовать

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

Лично я буду использовать этот подход. Вы можете просто поймать исключения и распечатать трассировку стека, если вам нужна информация.

Сделайте свою задачу на фоне вернуть логическое значение.

это вот так:

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

        @Override
                protected void onPostExecute(Boolean result) {

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

Другая возможность - использовать Object как тип возврата и в onPostExecute() Проверьте на наличие типа объекта. Это короткое.

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

Если вы знаете правильное исключение, вы можете вызвать

Exception e = null;

publishProgress(int ...);

например:

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

и перейти к "OnProgressUpdate" и сделайте фологу

@Override
protected void onProgressUpdate(final Integer... values) {

    // TODO Auto-generated method stub
    super.onProgressUpdate(values);
    mDialog.dismiss();
    OptionPane.showMessage(mActivity, "Connection error", e.getMessage());
}

Это будет полезно только в некоторых случаях. Также вы можете сохранить Global Exception переменная и получить доступ к исключению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top