Подтвердить что ты не робот

Фрагменты, заменяемые при выполнении AsyncTask, - NullPointerException в getActivity()

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

Используя что-то похожее на 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())
  • проверка if getActivity() null или вызов this.isDetached() (не реальное исправление, и мне нужно будет его проверять всякий раз, когда я вызываю getActivity() и т.д.)

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Сегодня я столкнулся с той же проблемой: когда я изменил отображаемый fragment, если AsyncTask еще не закончен, и он пытается получить доступ к view, чтобы заполнить его еще несколькими элементами, он будет верните a 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

Ответ 3

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