2012-06-18 5 views
13

У меня проблема с 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); 

ответ

16

Короткого исправления:

В методе onTabSelected, перед использованием if (mFragment == null) вам нужно, чтобы попытаться получить фрагмент (с использованием mFragment = getSupportFragmentManager().findFragmentByTag(mTag)). Вы также можете установить это извне, но я не вижу, как вы это делаете.

Проверка if(savedInstanceState == null) на onCreate также может решить эту проблему, и я считаю, что это лучший подход! :)

+0

Если я поместил свой код действия в метод onCreate, он не будет создан или не показан, когда активность будет воссоздана после изменения ориентации. Я попробую часть SupportManager сейчас – StuStirling

+0

+1 ... прокрасться там с правильным ответом во время редактирования. :) – Barak

+0

- это фрагмент, который не передается, когда он вызывает setTabListener? – StuStirling

8

Похоже, вы не имеете что-то в вашем onCreate методе, завернутые в if(savedInstanceState == null), так что вы создаете еще один фрагмент в дополнение к тому, восстанавливается из savedInstanceState пучка.

EDIT

присмотревшись на свой код, я думаю, что я был неправ о OnCreate, ваш onTabSelected должен обрабатывать его. Я думаю, что ваш if (mFragment == 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 
    } 
} 
+0

Мы говорим в моем фрагменте или моей основной деятельности? – StuStirling

+0

Я бы рискнул угадать вашу главную деятельность. Независимо от того, что вы настраиваете и отображает свое первоначальное представление. – Barak

+0

Я добавил свой метод onCreate к моему вопросу выше – StuStirling

2

я узнал, что setRetainInstance фактически игнорируется, и все фрагменты, созданные android.support.v4.app.FragmentManager сохраняются в onSaveInstanceState и воссозданы в onCreate.

Для меня решение было тупо удалить излишнюю сохраненный фрагмент: https://stackoverflow.com/a/13996054/341091

0

если (savedInstanceState == NULL) не работает всегда. иногда savedInstanceState! = null, пока вам нужно добавить другой фрагмент из-за ландшафтной ориентации.

Другой подход состоит в том, чтобы проверить, является ли fm.findFragmentById (R.id.frameLayoutLeft), независимо от ориентации, является нулевой или нет, если это так, чем создание нового экземпляра фрагмента в противном случае ничего не делает. Если вам нужен второй фрагмент в ландшафтном режиме, вам нужно сначала проверить, ландшафт ли он или нет, проверьте, является ли fm.findFragmentById (R.id.frameLayoutRight) нулевым или нет. если null, чем создавать, в противном случае ничего не делать, потому что он уже сохранен в ОС Android.

1

У меня была более-менее та же проблема, но представленные выше решения, похоже, не сработали в моей ситуации. В конце концов я нашел следующее решение:

@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); 
    } 
} 
Смежные вопросы