2012-06-18 18 views
13

Mam problem z Fragments i zmianą orientacji.Fragmenty nie działają poprawnie po zmianie orientacji

Mam aplikację, która ma MainActivity, która obsługuje przełączanie Fragments za pomocą paska akcji z zakładkami. Oto kod dla paska zadań z zakładkami i kiedy wybrana jest karta.

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) { 

    } 

Sposób, w jaki widzę, to to, że wszystko działa poprawnie, gdy aplikacja ładuje się najpierw w trybie portretu. Gdy się obracam, z jakiegoś powodu dodawane jest kolejne wystąpienie Fragment1, a następnie nie jest ono odłączane po wybraniu innej karty. Dzieje się tak również wtedy, gdy następnie obracam z powrotem do portretu.

Próbowałem używać setRetainInstance(true); w moim Fragments, ale to nie działa.

Czy istnieje metoda, którą należy zastąpić lub zrobić coś z moim Fragments przed obróceniem?

Z góry dziękuję.

EDIT Widziałem, że funkcja onTabSelected jest wywoływana ponownie po odtworzeniu działania. Czy to może być przyczyną mojego problemu z dołączaniem fragmentów więcej niż raz?

Oto moje działania na metodęCreate.

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); 

Odpowiedz

16

Short fix:

W metodzie onTabSelected, przed użyciem if (mFragment == null) trzeba postarać się o fragment (używając mFragment = getSupportFragmentManager().findFragmentByTag(mTag)). Możesz również ustawić to z zewnątrz, ale nie widzę, żebyś to robił.

Sprawdzanie if(savedInstanceState == null) na onCreate może również rozwiązać ten problem i uważam to za lepsze podejście! :)

+0

Jeśli umieściłem mój kod paskowy akcji w metodzie onCreate, nie zostanie on utworzony ani pokazany, gdy aktywność zostanie odtworzona po zmianie orientacji. Spróbuję teraz części supportManager – StuStirling

+0

+1 ... skradając się tam z właściwą odpowiedzią podczas edycji. :) – Barak

+0

to fragment nie jest przekazywany, gdy wywołuje setTabListener? – StuStirling

8

Brzmi to jak nie masz coś w sposobie onCreate zawinięte w if(savedInstanceState == null), więc tworzysz kolejny fragment oprócz jednej przywracana z wiązki savedInstanceState.

EDIT

Przyglądając się bliżej kodu, myślę myliłem o onCreate Twój onTabSelected powinien go obsłużyć. Myślę, że twój if (mFragment == null) zawsze będzie null, ponieważ nie próbujesz znaleźć fragmentu. Zmienić tę sekcję kodu do:

@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

Czy mówimy w moim fragmencie lub mojej głównej działalności? – StuStirling

+0

Zaryzykowałbym odgadnąć Twoją główną działalność. Cokolwiek cię ustawi i wyświetli twój początkowy widok. – Barak

+0

Dodałem moją metodę onCreate do mojego pytania powyżej – StuStirling

2

I okazało się, że setRetainInstance jest faktycznie ignorowana i wszystkie fragmenty stworzone przez android.support.v4.app.FragmentManager są przechowywane w onSaveInstanceState i są odtworzone w onCreate.

Dla mnie rozwiązaniem było dosadnie usunięcie nadmiernie zapisany fragment: https://stackoverflow.com/a/13996054/341091

0

if (savedInstanceState == null) nie działa zawsze. czasami savedInstanceState! = null, podczas gdy musisz dodać kolejny fragment ze względu na orientację poziomą.

Innym podejściem jest sprawdzenie, czy fm.findFragmentById (R.id.frameLayoutLeft), bez względu na to, jaka jest orientacja, jest puste lub nie, jeśli tak, to stwórz nową instancję fragmentu, w przeciwnym razie nic nie rób. Jeśli potrzebujesz drugiego fragmentu w trybie poziomym, musisz najpierw sprawdzić, czy jest krajobraz, czy nie, jeśli tak, sprawdź, czy fm.findFragmentById (R.id.frameLayoutRight) ma wartość null, czy nie. jeśli null, to create, w przeciwnym razie nic nie rób, ponieważ jest już tam zachowany przez system operacyjny Android.

1

Miałem mniej więcej ten sam problem, ale rozwiązania przedstawione powyżej nie sprawdziły się w mojej sytuacji. Ostatecznie znalazłem następujące rozwiązanie:

@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); 
    } 
} 
Powiązane problemy