Фрагменты не работают правильно после изменения ориентации
У меня проблема с Fragments
и изменением ориентации.
У меня есть приложение, которое имеет MainActivity
, который управляет переключением Fragments
через панель действий с вкладками. Вот код для панели вкладок и при выборе вкладки.
private class MyTabListener <T extends android.support.v4.app.Fragment> implements ActionBar.TabListener {
private android.support.v4.app.Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public MyTabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
@Override
public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one.
mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content,mFragment,mTag);
} else {
ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity
}
}
@Override
public void onTabUnselected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
if (mFragment != null){
ft.detach(mFragment); // when a fragment is no longer needed, detach it from the activity but dont destroy it
}
}
@Override
public void onTabReselected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
Как я вижу, все работает нормально, когда приложение загружается в портретном режиме. Когда я вращаюсь, по какой-то причине добавляется другой экземпляр Fragment1
, а затем не отделяется, когда выбрана другая вкладка. Это также имеет место, когда я поворачиваю назад к портрету.
Я попытался использовать setRetainInstance(true);
в моем Fragments
, но это не сработает.
Есть ли способ, с помощью которого мне нужно переопределить или сделать что-то с моим Fragments
перед вращением?
Спасибо заранее.
EDIT Теперь я видел, что onTabSelected вызывается снова, когда активность воссоздана. Может ли это быть причиной моей проблемы с присоединением фрагментов более одного раза?
Вот мои действия onCreate.
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
//setContentView(R.layout.main);
}
// Create the Action Bar with tabs
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
//create the tab for track and add it to the action bar.
Tab tab = actionBar.newTab()
.setText("Track")
.setTabListener(new MyTabListener<TrackingFragment>(this,"track",TrackingFragment.class));
actionBar.addTab(tab);
//create the tab for ski tracks and add it to the action bar.
tab = actionBar.newTab()
.setText("Something Tracks")
.setTabListener(new MyTabListener<TrackListFragment>(this,"somethingtracks",TrackListFragment.class));
actionBar.addTab(tab);
//create the tab for photos and add it to the action bar.
tab = actionBar.newTab()
.setText("Photos")
.setTabListener(new MyTabListener<PhotoFragment>(this,"photos",PhotoFragment.class));
actionBar.addTab(tab);
Ответы
Ответ 1
Короткое исправление:
В методе onTabSelected
перед использованием if (mFragment == null)
вам нужно попытаться получить фрагмент (используя mFragment = getSupportFragmentManager().findFragmentByTag(mTag)
). Вы также можете установить это извне, но я не вижу, как вы это делаете.
Проверка if(savedInstanceState == null)
на onCreate
также может решить эту проблему, и я считаю, что это лучший подход!:)
Ответ 2
Похоже, что у вас нет чего-то в вашем методе onCreate
, заключенном в if(savedInstanceState == null)
, поэтому вы создаете еще один фрагмент в дополнение к тому, который был восстановлен из пакета savedInstanceState.
ИЗМЕНИТЬ
Посмотрев более внимательно на свой код, я думаю, что я ошибся в onCreate, ваш onTabSelected должен его обработать. Я думаю, что ваш if (mFragment == null)
всегда имеет значение null, потому что вы не пытаетесь найти фрагмент. Измените этот раздел кода на:
@Override
public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); // add this
if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one.
mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content,mFragment,mTag);
} else {
ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity
}
}
Ответ 3
Я узнал, что setRetainInstance
фактически игнорируется, и все фрагменты, созданные android.support.v4.app.FragmentManager
, хранятся в onSaveInstanceState
и воссозданы в onCreate
.
Для меня решение заключалось в том, чтобы прямо удалить лишний сохраненный фрагмент: fooobar.com/questions/287435/...
Ответ 4
У меня была более или менее та же проблема, но приведенные выше решения, похоже, не работали в моей ситуации. В конце концов я нашел следующее решение:
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.replace(android.R.id.content, mFragment, mTag); // Use replace iso add
}
else {
ft.attach(mFragment);
}
}
Ответ 5
if (savedInstanceState == null) не работает всегда. иногда savedInstanceState!= null, пока вам нужно добавить другой фрагмент из-за ландшафтной ориентации.
Другой подход состоит в том, чтобы проверить, является ли fm.findFragmentById(R.id.frameLayoutLeft), независимо от того, что представляет собой ориентация, ноль или нет, если это так, чем создание нового экземпляра фрагмента, в противном случае ничего не делать. Если вам нужен второй фрагмент в ландшафтном режиме, вам нужно сначала проверить, не ландшафт или нет, если это так, проверьте, является ли fm.findFragmentById(R.id.frameLayoutRight) нулевым или нет. если null, чем create, в противном случае ничего не делать, потому что он уже сохранен ОС Android.