Странная ошибка жизненного цикла фрагмента

ИЗМЕНИТЬ

Таким образом, кажется, что мой Fragment сохраняется в FragmentManager, который пытается его повторно инициализировать. Все еще не уверен, почему он не уничтожается с помощью Activity. Что касается сообщения о загрузке, оно отображается, когда для ListView не установлен адаптер. Однако я установил элементы адаптера в onCreate и onResume, поэтому я не уверен, почему отображается этот экран загрузки. Все еще открыты для любых объяснений такого поведения

Исходный

Я играюсь с фрагментами и заметил странную ошибку, которая появляется, когда я меняю ориентацию экрана. Эта ошибка не должна возникать, потому что все данные воссоздаются в onCreate при изменении ориентации экрана. Кроме того, фрагмент onResume() вызывается дважды после поворота. Вот мои шаги по созданию ошибки и тому, как отладчик обращается к функциям.

  • Активность: onCreate()
  • Активность: onResume()
  • Фрагмент: onResume()
  • Повернуть экран
  • Активность: onCreate()
  • Активность: onResume()
  • Фрагмент: onResume() (элементы имеют значение null, хотя Activity.onResume() устанавливает их)
  • Фрагмент: onResume() (элементы не нулевые, почему это вызывается дважды?)

После нажатия на этот последний фрагмент onResume планшет отображает сообщение "Загрузка..." и значок. Почему данные больше не отображаются в списке? Я подозреваю, что onCreate создает второй фрагмент. Первый фрагмент теряет свои данные из-за того, что ориентация разрушает представления, второй фрагмент получает данные, а экран загрузки — это первый фрагмент без элементов данных, а второй фрагмент скрыт. Я могу ошибаться. Почему не все фрагменты уничтожаются при повороте экрана как Activity? Пожалуйста, не критикуйте код, если он не решает эту конкретную проблему. На самом деле я не делаю приложение, я экспериментирую с функциональностью фрагмента. Спасибо!

Основное действие

private ArrayList<Object> items = new ArrayList<Object>();
private MyListFragment mylistFragment;

public MainActivity() {
    items.add("Hello");
    items.add("World");
    items.add("Goodbye");
}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    FragmentManager fm = getFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();

    mylistFragment = new MyListFragment();
    mylistFragment.setItems(items);

    ft.add(R.id.container, mylistFragment);
    ft.commit();
}

@Override
public void onResume() {
    super.onResume();

    mylistFragment.setItems(items);
    mylistFragment.getListView().setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(MainActivity.this, ((TextView)view).getText(), Toast.LENGTH_LONG).show();
        }

    });
}

Фрагмент списка

private List<Object> items = null;
private Boolean isSet = false;

@Override
public void onResume() {
    super.onResume();
    if( !isSet && items != null) {
        setListAdapter(new ArrayAdapter<Object>(getActivity(), R.layout.item, items));
        isSet = true;
    }
}

public void setItems(List<Object> items) {
    this.items = items;
    if( this.isResumed() ) {
        setListAdapter(new ArrayAdapter<Object>(getActivity(), R.layout.item, items));
        isSet = true;
    } else {
        isSet = false;
    }
}

person Spidy    schedule 03.05.2011    source источник


Ответы (3)


FragmentManager автоматически воссоздаст для меня Fragment. Однако данные внутри них необходимо повторно инициализировать. Поэтому мой код создавал второй фрагмент. Экран загрузки был из-за того, что у первого фрагмента больше не было своего адаптера предметов, а второй фрагмент был скрыт. Какая головная боль, я почти думаю, что FragmentManager должен уничтожить Fragments, чтобы вы могли воссоздать их с данными, которые они содержат.

person Spidy    schedule 03.05.2011
comment
Извините, однако я не вижу ответа слишком ясно... как вы решили эту проблему? Я пришел к тому же выводу, что и вы, но не могу найти способ легко решить эту проблему. Имея в виду, как вы убиваете старые фрагменты и используете новые, которые были воссозданы. - person Maurycy; 16.03.2012
comment
Если вы хотите избавиться от старого фрагмента и использовать новый, используйте функцию FragmentTransaction.replace(). Затем старый будет заменен на новый. Просто знайте, что данные придется перезагружать. - person Spidy; 18.03.2012

Я считаю, что именно поэтому в различных демонстрациях через Diane и других примерах Google... обычно есть какой-то способ помочь инициализации hte с помощью статического метода... и setArguments.

IIRC, материал для создания фрагментов вызовет конструктор по умолчанию для создания, но знает только о заполнении соответствующими данными через setArguments. В примере в блоге разработки Android... идентификатор передавался из списка действий во фрагмент сведений. После вызова setParams менеджер фрагментов должен иметь возможность реанимировать его.

Документации по этому вопросу немного, и я хотел бы сделать все правильно, поэтому, если у вас есть отзывы, я был бы признателен.

person Ronnyek    schedule 06.05.2011

Кажется, что использование FragmentActivity из библиотеки поддержки автоматически сохраняет и восстанавливает экземпляр. Поэтому выполняйте транзакции фрагментов только в том случае, если savedInstanceState равно null.

Например, в вашем FragmentActivity onCreate() сделайте следующее:

if(savedInstanceState == null){
       FragmentManager fragmentManager = getSupportFragmentManager();
       fragmentManager.beginTransaction()
       .replace(R.id.fragment_container, mFragment).commit(); //mFragment is your own defined fragment
}
person yazjisuhail    schedule 14.05.2014