Вопрос по android, exception-handling – Поймать исключение AsyncTask. Нужно думать

8

Я хочу поймать исключение потока в doInBackground и напечатать сообщение об ошибке в onPostExcecute. Проблема в том, что у меня нет объекта Throwable в onPostExecute. Какcatch Exception in non-UI thread а такжеprint the error message in UI-thread?

public class TestTask extends AsyncTask<Void, Void, List<String>> {

    @Override
    protected List<String> doInBackground(final Void... params) {
        try {
            ...
            return listOfString;
        } catch(SomeCustomException e) {
            ...
            return null;
        }       
    }

    @Override
    protected void onPostExecute(final List<String> result) {
        if(result == null) {
            // print the error of the Throwable "e".
            // The problem is I don't have the Throwable object here! So I can't check the type of exception.
        }

    }
}

Update after Arun's answer:

Это мой класс-оболочка AsyncTask. Он намеревается обработать Exception в doInBackground, но я не могу найти хорошего решения для этого.

public abstract class AbstractWorkerTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result>
implements Workable {
    protected OnPreExecuteListener onPreExecuteListener;
    protected OnPostExecuteListener<Result> onPostExecuteListener;
    protected ExceptionHappenedListener exceptionHappendedListener;
    private boolean working;

    @Override
    protected void onPreExecute() {
        if (onPreExecuteListener != null) {
            onPreExecuteListener.onPreExecute();
        }
        working = true;
    }

    @Override
    protected void onPostExecute(final Result result) {
        working = false;
        if(/* .........*/ ) {
            exceptionHappendedListener.exceptionHappended(e);
        }
        if (onPostExecuteListener != null) {
            onPostExecuteListener.onPostExecute(result);
        }
    }

    @Override
    public boolean isWorking() {
        return working;
    }

    public void setOnPreExecuteListener(final OnPreExecuteListener onPreExecuteListener) {
        this.onPreExecuteListener = onPreExecuteListener;
    }

    public void setOnPostExecuteListener(final OnPostExecuteListener<Result> onPostExecuteListener) {
        this.onPostExecuteListener = onPostExecuteListener;
    }

    public void setExceptionHappendedListener(final ExceptionHappenedListener exceptionHappendedListener) {
        this.exceptionHappendedListener = exceptionHappendedListener;
    }

    public interface OnPreExecuteListener {
        void onPreExecute();
    }

    public interface OnPostExecuteListener<Result> {
        void onPostExecute(final Result result);
    }

    public interface ExceptionHappenedListener {
        void exceptionHappended(Exception e);
    }
}
Приятель, я имел в виду магазинe.ToString() на 1-м месте списка, а затем проверьте то же самое вonPostExecute()... GAMA
Я попробовал, но не могу вернуть и Exception, и List & lt; String & gt; в doInBackground. Как это сделать? Emerald Hieu
@GAMA: эй, вы не можете, потому что тип возвращаемого значения - List & lt; String & gt ;, а не String. Синтаксическая ошибка конечно. Emerald Hieu
Вы можете реализовать своего рода обратные вызовы для установки и получения ошибки. Paresh Mayani
попробуйте вернутьсяe.toString() вместоnull отcatch изdoInBackground()... GAMA

Ваш Ответ

3   ответа
4

Изменение типа возвратаdoInBackground вObject возможно пройтиException а затем использоватьinstanceof() является источником запаха кода (плохая практика программирования). Всегда предпочтительнее ограничить тип возвращаемого вами значения тем, что вы хотите вернуть.

Основываясь на этомответ просто добавьте приватный член для хранения исключенияdoInBackground а затем проверить это первым делом вonPostExecute.

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

Общий пример (тело AsyncTask):

private Exception mException

@Override
protected Result doInBackground(Params... params) {
    try {
          // --- Do something --- //
    }
    catch( SomeException e ){ mException = e; return null; }
}

@Override
protected void onPostExecute(Result result) {
    if (mException != null) {
        // --- handle exception --- //
        return;
    }

    // --- Perform normal post execution actions --- //
}
4

Просто сохраните Исключение в списке и обработайте его позже, так как onPostExecute () всегда вызывается после doInBackground ():

public class TestTask extends AsyncTask<Params, Progress, Result> {

  List<Exception> exceptions = new ArrayList<Exception>();

  @Override
  protected Result doInBackground(Params... params) {
    try {
      ...
    } catch(SomeCustomException e) {
      exceptions.add(e);
    }
    return result;
  }

  @Override
  protected void onPostExecute(Result result) {
    for (Exception e : exceptions) {
      // Do whatever you want for the exception here
      ...
    }
  }

}

Это выполнимо, но редко используется, так как в большинстве случаев мы хотим обработать исключение, как только оно будет сгенерировано и перехвачено:

public class TestTask extends AsyncTask<Params, Progress, Result> {

  @Override
  protected Result doInBackground(Params... params) {
    try {
      ...
    } catch(SomeCustomException e) {
      // If you need update UI, simply do this:
      runOnUiThread(new Runnable() {
        public void run() {
          // update your UI component here.
          myTextView.setText("Exception!!!");
        }
      });
    }
    return result;
  }

}

Надеюсь, это имеет смысл.

7

Изменить тип возвратаdoInBackground() вObject и когда вы получите результат вonPostExecute(Object result) использоватьinstanceOf оператор, чтобы проверить, является ли возвращенный результатException илиList<String>.

Edit

Поскольку результатом может быть либо исключение, либо правильный список, вы можете использовать следующее:

protected void onPostExecute(final Object result) {
    working = false;
    if(result instanceof SomeCustomException) {
        exceptionHappendedListener.exceptionHappended(result);
    }
    else{
        if (onPostExecuteListener != null) {
            onPostExecuteListener.onPostExecute(result);
        }
    }
}

Также измените следующее утверждение:

public abstract class AbstractWorkerTask<Params, Progress, Object> extends AsyncTask<Params, Progress, Object>
Это хорошо, но не решает проблему, потому что вы не можете использовать экземпляр параметризованного типа (List & lt; String & gt;). : [ Emerald Hieu

Похожие вопросы