Ошибка жизненного цикла виртуального фрагмента
ИЗМЕНИТЬ
Итак, мой 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
}