Ошибка жизненного цикла виртуального фрагмента

ИЗМЕНИТЬ

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

Оригинал

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

  • Деятельность: onCreate()
  • Активность: onResume()
  • Фрагмент: onResume()
  • Поворот экрана
  • Деятельность: onCreate()
  • Активность: onResume()
  • Фрагмент: onResume() (элементы являются нулевыми, хотя 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;
    }
}

Ответы

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

Кажется, что использование 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
}