Фрагменты, заменяемые во время выполнения AsyncTask - исключение NullPointerException для getActivity () - PullRequest
20 голосов
/ 28 ноября 2011

Я недавно преобразовал свои действия во фрагменты.

Используя что-то похожее на Tab-Navigation, фрагменты заменяются, когда пользователь выбирает другую вкладку. После заполнения фрагмента я запускаю хотя бы один AsyncTask для получения информации из Интернета. Однако - если пользователь переключается на другую вкладку так же, как выполняется метод doBackground из моей AsyncTask - фрагмент заменяется , и поэтому я получаю NullPointerException в отмеченных строках:

@Override
protected Object doInBackground(Object... params) {
  ...
  String tempjson = helper.SendPost(getResources().getText(R.string.apiid)); //ERROR: Fragment not attached
  ...
}

protected onPostExecute(Object result) {
  ...
  getActivity().getContentResolver() //NULLPOINTEREXCEPTION
  getView().findViewById(R.id.button) //NULL
  ...
}

getActivity() и getResources() вызывают ошибку, поскольку мой фрагмент заменен.

То, что я пробовал:

  • Вызов метода отмены в моей AsyncTask (не исправит ни первую, ни вторую ошибку, если фрагмент будет заменен во время выполнения onPostExecute())
  • проверка, является ли getActivity() null или вызов this.isDetached() (не реальное решение, и мне нужно проверять это всякий раз, когда я звоню getActivity() и т. Д.)

Итак, мой вопрос: что было бы лучше, чтобы избавиться от этих проблем AsyncTask? У меня не было этих проблем при использовании Activity, так как они не были «убиты» / отсоединены при смене вкладок (что привело к более высокому использованию памяти - причина, по которой я люблю переключаться на фрагменты)

Ответы [ 3 ]

18 голосов
/ 28 ноября 2011

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

Две другие альтернативы:

  • Используйте Loaders, онипредназначен для более приятного воспроизведения фрагментов
  • Переместите загрузку AsyncTask в родительское действие и используйте интерфейсы для отделения от фрагментов.Операция будет знать, есть ли фрагмент или нет, и действовать соответствующим образом (возможно, отбрасывая результат, если фрагмент исчезнет).
4 голосов
/ 09 февраля 2014

Сегодня я столкнулся с той же проблемой: когда я изменил отображаемое fragment, если AsyncTask еще не закончил, и он пытается получить доступ к view, чтобы заполнить его еще несколькими элементами, это вернуть NullPointerException.

Я решил проблему, перекрывающую один метод жизненного цикла фрагментов: onDetach(). Этот метод вызывается в тот момент, когда fragment отсоединяется от activity.

Вам нужно вызвать метод cancel() для вашего AsyncTask. Это остановит выполнение задачи, избегая NullPointerExecption.

Вот пример onDetach():

@Override
public void onDetach() {
    super.onDetach();
    task.cancel(true);
}

Проверьте эту страницу, чтобы получить больше информации о жизненном цикле фрагментов: http://developer.android.com/reference/android/app/Fragment.html#Lifecycle И это, чтобы посмотреть больше об отмене задачи: http://developer.android.com/reference/android/os/AsyncTask.html

0 голосов
/ 01 декабря 2011

Вы пытались вызвать setRetainInstance(true); в функции onCreate() вашего класса фрагмента?

...