Fragment w ViewPager używający FragmentPagerAdapter jest pusty po drugim wyświetleniu

98

Mam interfejs fragmentów z zakładkami na dole, które otwierają różne fragmenty w głównym widoku.

Mam jeden konkretny fragment, który jest listą pozycji. Jeśli użytkownik wybierze jedną z pozycji na tej liście, otwiera się kolejny fragment zawierający przeglądarkę, która przewija się w poziomie pomiędzy wszystkimi pozycjami na liście w poprzednim fragmencie. To działa świetnie.

Viewpager używa FragmentPagerAdapter do wyświetlenia elementów.

Problem pojawia się, gdy użytkownik wybiera element na liście, wyświetla go, a następnie naciska przycisk na pasku kart, aby wrócić do listy, a następnie wybiera inny element. Za drugim razem, gdy element jest zaznaczony, zamiast przeglądarki pojawia się pusty ekran. W takim przypadku w moim LogCacie nie pojawiają się żadne błędy.

Dlaczego przeglądarka pojawia się tylko za pierwszym razem?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}
howettl
źródło

Odpowiedzi:

221

Miałem ten sam problem. Zmiana klasy nadrzędnej mojego PageAdaptera z, android.support.v4.app.FragmentPagerAdapteraby android.support.v4.app.FragmentStatePagerAdapterrozwiązać ViewPagerproblem z wyświetlaniem przy „drugim czasie”!

Yann
źródło
2
Bez żartów? Nie mam już tego kodu, inaczej bym go przetestował. Być może ta odpowiedź pomoże komuś innemu.
howettl
10
Co za gość! Szukałem tego rozwiązania przez wiele dni! Dzięki za ton, działa jak urok. Ale deweloper we mnie pyta, jaki wpływ ma ta zmiana? Mam na myśli, dlaczego wcześniej to nie działało i dlaczego w StatePagerAdapter
Anand Sainath
1
musisz także @Override public int getItemPosition (obiekt Object) {return POSITION_NONE; }
Helin Wang
1
Dla mnie też zadziałało. Oto link. Wydaje się, że zachowuje stan fragmentu, co robi różnicę. developer.android.com/reference/android/support/v4/app/…
Tjaart
1
To przypadek, że to działa, prawidłowa odpowiedź brzmi: @Daniel F. W każdym razie, dla wygody komentujących tutaj, różnica między FragmentPagerAdapteri FragmentStatePagerAdapterjest w tym pierwszym jest bardziej odpowiedni dla kilku stron, zachowuje wszystkie fragmenty w pamięci, dzięki czemu ma najlepsze wyniki przy przełączaniu stron, podczas gdy ten drugi jest bardziej odpowiedni dla wielu stron, niszczy fragmenty, zachowując tylko ich stan, jest bardziej wydajna w pamięci, ale trochę wolniejsza na przełączaniu stron.
Cristina De Rito
87

Udało mi się rozwiązać ten problem poprzez zastąpienie getFragmentManager()ze getChildFragmentManager()we fragmencie nadrzędnym. Ten fragment nadrzędny tworzył instancję android.support.v4.app.FragmentPagerAdapter w celu zawarcia stronicowanych (przesuwalnych) fragmentów, co wymaga menedżera fragmentów w konstruktorze. Do tego konstruktora przekazałem zwracaną wartość getChildFragmentManager().

Kluczem był link hackbod ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), który został znaleziony w tym poście Fragments within Fragments

Aby zagnieździć fragment, po prostu wywołaj getChildFragmentManager()Fragment, do którego chcesz dodać fragment. Zwraca to FragmentManager, którego można używać tak, jak zwykle w działaniu najwyższego poziomu do tworzenia transakcji fragmentarycznych.

Daniel F.
źródło
Dziękuję ... miałem podobny problem, próbując ponownie utworzyć instancję widoku przesuwanych zakładek po onresume (), który zawierał fragmentpageradapter ... samouczek, którego użyłem, był z 2016 roku i nadal musiałem zmienić go na fragmentstatepageradapter, aby go uzyskać praca. Żałuję, że nie wiedziałem DLACZEGO.
Nerdy Bunz
ta odpowiedź zaoszczędziła mi dużo czasu. Ponieważ FragmentStatePagerAdaptersamo użycie nie rozwiązuje zadanego tutaj pytania. wraz z FragmentStatePagerAdapterw rodzicielskim fragmencie YourAdapter adapter = new YourAdapter (getChildFragmentManager()); należy dodać
MMK
17

dla mnie musiałem to nazwać na moim podglądzie:

myViewPager.setSaveFromParentEnabled(false);

Miałem problem, w którym przeglądarka nie odświeżała się, a jedyne, co widziałem, to pusty biały ekran, w którym powinny znajdować się fragmenty. Przechodziłem przez getChildFragmentManager, ale to nie pomogło.

j2emanue
źródło
1
Dlaczego na świecie to zadziałało? To rozwiązało mój problem, ale nie mam pojęcia, dlaczego.
ClayHerendeen
Usunąłem go teraz z mojego kodu. Menedżer fragmentów powodował problem. Spróbuj przełączać się między getchildfragmentmanager i getfragmentmanager
j2emanue
Już tego próbowałem. Mam zagnieżdżone karty, każda z ViewPagerami, które wyłączyły przesuwanie. Wiem, że to kiepski projekt, ale klienci nie życzą mi tego. Używam childFragmentManager na pasku kart najwyższego poziomu. Przełączanie na niższy poziom tabbar / viewpager nie rozwiązało problemu. Przypuszczam, że na razie będę trzymał się setSaveFromParentEnabled (false), ponieważ działa.
ClayHerendeen
Czy korzystasz z najnowszej biblioteki wsparcia
j2emanue
2
Miałem ten sam problem z ostatnich 2 dni .. Twoje rozwiązanie zadziałało dla mnie. dzięki !
brijexecon
11

W moim bardzo szczególnym przypadku, gdy korzystałem z CoordinatorLayout z AppBarLayout i ViewPager, tym, co mnie rozwiązało, było usunięcie androida: fitSystemWindows = "true" z moich właściwości xml AppBarLayout .

Nie pytaj mnie dlaczego. Wiem, że brzmi to trochę absurdalnie i jakby nie powinno mieć żadnej korelacji, ale to właśnie ta pojedyncza linia była jedyną rzeczą, która powodowała problemy, ponieważ już używałem getChildFragmentManager () w moim adapterze. Spędziłem cały dzień na debugowaniu mojego kodu, aby to znaleźć, więc mam nadzieję, że zaoszczędzi to komuś innego czasu.

emirua
źródło
3
O rany ... Prawie się poddam z tym problemem. Zrobiłeś mój cholerny dzień! Jezu Google, WTF jest źle z AppBarLayout? Przejrzałem prawie sto stron i spędziłem mnóstwo godzin na debugowaniu, próbując rozwiązać ten problem bez powodzenia. Jestem naprawdę wdzięczny, że w końcu udało mi się rozwiązać problem za pomocą twojego komentarza. Wielkie dzięki! PS: Byłem tak zdesperowany, że nawet stworzyłem numer w AOSP: code.google.com/p/android/issues/… XD
Guillem Roca
Dzięki za podpowiedź. Przynajmniej pomogło nam to w rozwiązaniu problemu. Teraz próbujemy znaleźć opcję zrobienia tego na pełnym ekranie
Paresh Mayani
Jesteś ratownikiem! Nie miałem pojęcia, dlaczego mam ten problem i nadal nie miałem pojęcia, dlaczego to zadziałało!
nandu
10

Miałem ten sam problem, dla którego zmieniłem adapter z FragmentPagerAdapterna FragmentStatePagerAdapteriw getFragmentManager()nadrzędnym fragmencie nagetChildFragmentManager()

Przyczyna tego jest FragmentStatePagerAdapterpomocna w przechowywaniu dużej liczby stron, a pamięć związana z każdą odwiedzaną stroną jest mniejsza, ponieważ zachowuje tylko zapisany stan fragmentu, podczas gdy strona nie jest widoczna. Zmniejsza to obciążenie podczas przełączania między fragmentami.

Yashaswi NP
źródło
4

Spróbować umieścić setOffscreenPageLimit (int limit)na macierzystej ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

To zadziałało na mnie jak urok.

W moim przypadku miałem fragment wnętrza TabLayoutzViewPager.

I jeszcze jeden ViewPagerwewnątrz tego fragmentu. Za pierwszym razem wszystko działało dobrze, ale kiedy zmieniam kartę i wracam, część mojego fragmentu zniknęła.

Rumit Patel
źródło
1
Dobra odpowiedź. To mi pomogło.
Thirumalvalavan
2

To by ci pomogło.

    viewPager.setOffscreenPageLimit(position);
Pardeep Singh
źródło
1

Rozwiązaliśmy ten problem, ponownie implementując elementy pagera widoku jako standardowe widoki zamiast fragmentów i odpowiednio zmieniając adapter.

howettl
źródło
można spróbować usunięcie isViewFromObject (view, object Object) Funkcja
Mina Samy
Musi być lepszy sposób ....: / chociaż im bardziej zagłębiam się w Androida, tym mniej dojrzałe zdaję sobie sprawę, że jest.
StackOverflowed
1
Zagnieżdżone fragmenty nie są obsługiwane , więc ponowne wdrożenie w widoku standardowym wydaje się dobrym rozwiązaniem.
Sylphe
Zmagam się z podobnym problemem. Próbowałem użyć PagerAdapter zamiast FragmentAdapter, ale nadal napotykam ten sam problem. Proszę pomóż mi !
Gaurav Arora
Jeśli chcesz użyć zagnieżdżonych fragmentów, możesz użyć adaptera, który
podałem
1

Otrzymałem ten sam problem na platformie Xamarin Android z pustym ekranem za drugim razem .. Ustawienie poniższego rozwiązało problem.

viewPager.SaveFromParentEnabled = false;
Gerard
źródło
0

Możesz również zainicjować adapter w przypadkach, w których występuje ten błąd, gdy aplikacja jest zminimalizowana, a później wywoływana.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}
Patrick
źródło
0

Miałem to samo, gdy po raz drugi wywołuję adapter pagera, widok potomny zwraca wyjątek NullPointerException. A zmiana adaptera w FragmentStatePagerAdapter rozwiązuje również mój problem.

Arka-57
źródło
0

Zmień FragmentPagerAdapterna FragmentStatePagerAdapter Użyj getChildFragmentManager()zamiastgetFragmentManager()

getChildFragmentManager()- ponieważ zgodnie z dokumentacją zwróci prywatny FragmentManager do umieszczania i zarządzania fragmentami wewnątrz tego fragmentu. W międzyczasie getFragmentManager()zwróci FragmentManager do interakcji z fragmentami powiązanymi z tym działaniem

Mostafa Anter
źródło
0

klasa ViewPagerAdapter rozszerza FragmentStatePagerAdapter tę pracę dla mnie spróbuj tego

Abdul Basit Abbasi
źródło