48

Mam Fragment (będę to nazwać pagerFragment), który jest dodany do backstack i jest widoczny. Posiada viewPager z FragmentPagerAdapter. FragmentPagerAdapter zawiera (powiedzmy) dwa fragmenty: A i B.Nawigacja z powrotem do FragmentPagerAdapter -> fragmenty są puste

Pierwsze dodanie fragmentów działa świetnie.

Fragment A ma przycisk, który po kliknięciu dodaje fragment (C) do backstacku.

Problem polega na tym, że jeśli dodaję ten fragment (C), a następnie kliknę z powrotem, pagerAdapter jest pusty i nie widzę w nim żadnych fragmentów.

Jeśli użyję haka i zniszczę fragmenty dzieci (A i B) w pagerFragment s onDestroyView(), to rozwiązuje problem, chociaż nie będę go używał.

Jakieś pomysły na temat problemu?

+0

Ewentualny duplikat [Fragment w ViewPager przy użyciu FragmentPagerAdapter jest pusty przy drugim wyświetleniu] (http://stackoverflow.com/questions/7746652/fragment-in-viewpager-using-fragmentpageradapter-is-blank-the- drugi raz-to-jest) – blahdiblah

Odpowiedz

11

Wygląda na to, że używasz zagnieżdżonych fragmentów, ponieważ twój ViewPager znajduje się wewnątrz PagerFragment. Czy zdałeś getChildFragmentManager() do konstruktora swojego FragmentPagerAdapter? Jeśli nie, powinieneś.

Nie sądzę, że potrzebujesz FragmentStatePagerAdapter, ale oddałbym go, ponieważ zajmuje się zapisywaniem i przywracaniem stanu Fragmentu. Fakt, że twój haker onDestroyView() działa, sprawia, że ​​myślę, że możesz potrzebować FragmentStatePagerAdapter.

Może to również mieć coś wspólnego ze sposobem, w jaki FragmentPagerAdapter dodaje Fragmenty. FragmentPagerAdapter nie dodaje fragmentów do backstack. Wyobraź sobie, że masz 10 lub więcej stron dodanych do ViewPagera i użytkownik przeskoczył przez nie. Użytkownik musiałby cofnąć się 11 razy, aby wycofać się z aplikacji.

Może to być również związane ze stanowiskiem: Nested Fragments and The Back Stack.

Również nie jestem pewien, do czego dodajesz fragment C do. Czy dodajesz go do tego samego kontenera co ViewPager?

Przynajmniej masz kilka opcji do zbadania. W takich sytuacjach lubię debugować kod źródłowy Androida SDK i sprawdzać, co powoduje jego zachowanie. Polecam pobranie AOSP source i dodanie frameworków/wsparcia i frameworków/bazy jako źródeł SDK. To jedyny prawdziwy sposób na zrozumienie, co się dzieje, i unikanie przypadkowych zmian, dopóki wszystko nie zadziała.

75

Miałem ten sam problem. Rozwiązaniem dla mnie było proste:

w onCreateView miałem:

// Create the adapter that will return a fragment for each of the three 
// primary sections of the app. 
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity() 
    .getSupportFragmentManager()); 

gdzie SectionPageAdapter jest coś takiego:

class SectionsPagerAdapter extends FragmentPagerAdapter { 
... 
} 

po zmianie getSupportFragmentManager do

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager()); 

zaczęło pracujący! Mam nadzieję, że to pomoże.

+2

getChildFragmentManager() działa tylko 17+ android sdk. :( –

+5

@SachinShelke musisz użyć biblioteki pomocy technicznej.;) Http://developer.android.com/reference/android/support/v4/app/Fragment.html#getChildFragmentManager%28%29 – Sufian

+0

@ mike-mitterer, niesamowita odpowiedź, jesteś niesamowity, bardzo dziękuję – Tom

0

Po prostu stanąłem przed problemem w naszym projekcie.Główną przyczyną jest sposób działania FragmentPagerAdapter:

FragmentPagerAdapter po prostu odłącza Fragment, którego obecnie nie potrzebuje z Widoku, ale nie usuwa go z jego FragmentManager. Kiedy chce ponownie wyświetlić Fragment, sprawdza, czy FragmentManager nadal zawiera Fragment przy pomocy znacznika utworzonego z ID widoku ViewPagera i identyfikatora zwróconego przez wywołania getItemId (pozycja) adapterów. Jeśli znajdzie Fragment, po prostu planuje dołączenie Fragmentu do swojego Widoku w ramach transakcji aktualizacji FragmentManager. Tylko wtedy, gdy nie znajdzie Fragmentu w ten sposób, tworzy nowy za pomocą adaptera getItem (pozycja) call!

Problem z Fragmentem zawierającym ViewPager z FragmentPagerAdapter polega na tym, że zawartość FragmentManager nigdy nie jest czyszczona, gdy zawierający Fragment jest umieszczany na tylnym stosie. Jeśli Fragment zawierający powraca z tylnego stosu, tworzy nowy widok, ale FragmentManager nadal zawiera fragmenty dołączone do starego widoku, a dołączenie istniejącego fragmentu już nie działa.

Najprostszym sposobem na pozbycie się tego problemu jest uniknięcie zagnieżdżonych fragmentów. :)

Drugi najprostszy sposób to, jak już wspomniano w innych postach, używanie programu ChildFragmentManager dla FragmentPagerAdapter, ponieważ jest on prawidłowo aktualizowany podczas cyklu życia fragmentu kontenera.

Ponieważ istnieją projekty (jak mój obecny), w których obie opcje nie są możliwe, opublikowałem tutaj rozwiązanie, które działa z dowolnym FragmentManager, używając hashCode z podstrony jako element id fragmentu w tym pozycja. Dostaje się za cenę przechowywania wszystkich fragmentów dla wszystkich pozycji w adapterze.

public class MyPagerAdapter extends FragmentPagerAdapter { 

private static int COUNT = ...; 
private final FragmentManager fragmentManager; 
private Fragment[] subFragments = new Fragment[COUNT]; 
private FragmentTransaction cleanupTransaction; 

public MyPagerAdapter(FragmentManager fragmentManager) { 
    super(fragmentManager); 
    this.fragmentManager = fragmentManager; 
} 

@Override 
public Fragment getItem(int position) { 
    return getSubFragmentAtPosition(position); 
} 

@Override 
public int getCount() { 
    return COUNT; 
} 

@Override 
public long getItemId(int position) { 
    return getSubFragmentAtPosition(position).hashCode(); 
} 

//The next three methods are needed to remove fragments no longer used from the fragment manager 
@Override 
public void startUpdate(ViewGroup container) { 
    super.startUpdate(container); 
    cleanupTransaction = fragmentManager.beginTransaction(); 
} 

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    super.destroyItem(container, position, object); 
    cleanupTransaction.remove((Fragment) object); 
} 

@Override 
public void finishUpdate(ViewGroup container) { 
    super.finishUpdate(container); 
    cleanupTransaction.commit(); 
} 

private Fragment getSubFragmentAtPosition(int position){ 
    if (subFragments[position] == null){ 
     subFragments[position] = ...; 
    } 
    return subFragments[position]; 
} 

}

0

Zastosowanie getChildFragmentManager() zamiast getSupportFragmentManager(). Będzie działać dobrze.

Powiązane problemy