Fragment in ViewPager mit FragmentPagerAdapter ist beim zweiten Anzeigen leer

98

Ich habe eine Fragmentoberfläche mit Registerkarten am unteren Rand, die verschiedene Fragmente in der Hauptansicht öffnen.

Ich habe ein bestimmtes Fragment, das eine Liste von Elementen ist. Wenn der Benutzer eines der Elemente in dieser Liste auswählt, wird ein weiteres Fragment geöffnet, das einen Viewpager enthält, der horizontal zwischen allen Elementen in der Liste im vorherigen Fragment scrollt. Das funktioniert super.

Der Viewpager verwendet einen FragmentPagerAdapter, um die Elemente anzuzeigen.

Das Problem tritt auf, wenn der Benutzer ein Element in der Liste auswählt, es anzeigt, dann auf die Schaltfläche in der Registerkartenleiste klickt, um zur Liste zurückzukehren, und dann ein anderes Element auswählt. Bei der zweiten Auswahl eines Elements wird anstelle des Viewpagers ein leerer Bildschirm angezeigt. In diesem Fall erhalte ich keine Fehler in meinem LogCat.

Warum wird der Viewpager nur beim ersten Mal angezeigt?

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
quelle

Antworten:

221

Ich hatte das gleiche Problem. Ändern der übergeordneten Klasse meines PageAdapters von android.support.v4.app.FragmentPagerAdapter, android.support.v4.app.FragmentStatePagerAdapterum mein ViewPagerAnzeigeproblem beim "zweiten Mal" zu lösen !

Yann
quelle
2
Im Ernst? Ich habe diesen Code nicht mehr, sonst würde ich ihn testen. Vielleicht hilft diese Antwort jemand anderem.
Howettl
10
Was für ein Mann! Ich war tagelang auf der Suche nach dieser Lösung! Vielen Dank Mann, funktioniert wie ein Zauber. Aber der Entwickler in mir fragt, welche Auswirkungen diese Änderung hat. Ich meine, warum hat es vorher nicht funktioniert und warum in StatePagerAdapter
Anand Sainath
1
Außerdem müssen Sie @Override public int getItemPosition (Objektobjekt) {return POSITION_NONE; }
Helin Wang
1
Hat auch für mich gearbeitet. Hier ist ein Link. Es scheint den Fragmentzustand zu retten, was den Unterschied ausmacht. developer.android.com/reference/android/support/v4/app/…
Tjaart
1
Es ist ein Zufall, dass dies funktioniert. Die richtige Antwort ist die von @Faniel F. Wie auch immer, der Einfachheit halber ist der Unterschied zwischen FragmentPagerAdapterund FragmentStatePagerAdapterbesteht darin, dass Ersteres für wenige Seiten besser geeignet ist. Alle Fragmente bleiben im Speicher, wodurch die besten Leistungen beim Seitenwechsel erzielt werden, während Letzteres für viele Seiten besser geeignet ist Seiten, es zerstört Fragmente, behält nur ihren Zustand bei, es ist speichereffizienter, aber beim Seitenwechsel etwas langsamer.
Cristina De Rito
87

Ich habe es geschafft, dies durch Ersetzen getFragmentManager()durch getChildFragmentManager()im übergeordneten Fragment zu lösen . Dieses übergeordnete Fragment instanziierte einen android.support.v4.app.FragmentPagerAdapter, um pageable (verschiebbare) Fragmente zu enthalten, für die ein Fragmentmanager im Konstruktor erforderlich ist. An diesen Konstruktor habe ich den Rückgabewert von übergeben getChildFragmentManager().

Der Link von hackbod war der Schlüssel ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), der in diesem Beitrag Fragmente in Fragmenten gefunden wurde

Um ein Fragment zu verschachteln, rufen getChildFragmentManager()Sie einfach das Fragment auf, in dem Sie ein Fragment hinzufügen möchten. Dies gibt einen FragmentManager zurück, den Sie wie gewohnt aus der Aktivität der obersten Ebene verwenden können, um Fragmenttransaktionen zu erstellen.

Daniel F.
quelle
Vielen Dank ... Ich hatte ein ähnliches Problem beim Versuch, eine Ansicht mit verschiebbaren Registerkarten nach onresume (), die einen Fragmentpageradapter enthielt, erneut zu instanziieren Arbeit. Ich wünschte, ich wüsste WARUM.
Nerdy Bunz
Diese Antwort hat mir viel Zeit gespart. Denn nur mit FragmentStatePagerAdapterwird die hier gestellte Frage nicht gelöst. zusammen mit FragmentStatePagerAdapterim übergeordneten Fragment YourAdapter adapter = new YourAdapter (getChildFragmentManager()); muss hinzugefügt werden
MMK
17

für mich musste ich das auf meinem viewpager aufrufen:

myViewPager.setSaveFromParentEnabled(false);

Ich hatte das Problem, dass der Viewpager nicht aktualisiert wurde und ich nur einen leeren weißen Bildschirm sah, auf dem sich die Fragmente befinden sollten. Ich habe getChildFragmentManager übergeben, aber es hat nicht geholfen.

j2emanue
quelle
1
Warum in aller Welt hat das funktioniert? Dies hat mein Problem behoben, aber ich habe keine Ahnung warum.
ClayHerendeen
Ich habe es jetzt aus meinem Code entfernt. Der Fragmentmanager hat das Problem verursacht. Versuchen Sie, zwischen getchildfragmentmanager und getfragmentmanager umzuschalten
j2emanue
Das habe ich schon versucht. Ich habe Registerkarten mit ViewPagern verschachtelt, die das Wischen deaktiviert haben. Ich weiß, dass dies schlechtes Design ist, aber die Kunden wünschen nicht meine. Ich benutze einen childFragmentManager für die oberste Registerkarte. Das Umschalten auf die untere Registerkarte / den Viewpager schien das Problem nicht zu beheben. Ich nehme an, ich werde mich vorerst an setSaveFromParentEnabled (false) halten, da es funktioniert.
ClayHerendeen
Verwenden Sie die neueste Support-Bibliothek
j2emanue
2
Ich hatte in den letzten 2 Tagen das gleiche Problem. Ihre Lösung hat bei mir funktioniert. Vielen Dank !
Brijexecon
11

In meinem speziellen Fall, in dem ich ein CoordinatorLayout mit einem AppBarLayout und dem ViewPager verwendet habe, wurde das Problem für mich gelöst, indem ich das Android: fitSystemWindows = "true" aus meinen AppBarLayout-XML-Eigenschaften entfernte .

Frag mich nicht warum. Ich weiß, es klingt ein bisschen lächerlich und sollte keine Korrelation haben, aber es war diese einzige Zeile, die das einzige Problem verursachte, da ich bereits getChildFragmentManager () in meinem Adapter verwendet habe. Ich habe einen ganzen Tag damit verbracht, meinen Code zu debuggen, um dies zu finden. Ich hoffe, dass dies jemand anderem Zeit spart.

Emirua
quelle
3
Oh Mann ... ich würde mich mit diesem Thema fast ergeben. Du hast meinen verdammten Tag gemacht! Meine Güte Google, WTF ist falsch mit dem AppBarLayout? Ich habe fast hundert Seiten durchgesehen und eine Menge Stunden mit dem Debuggen verbracht, um dieses Problem ohne Glück zu lösen. Ich bin wirklich dankbar, dass ich es endlich geschafft habe, das Problem mit Ihrem Kommentar zu lösen. Vielen Dank! PS: Ich war so verzweifelt, dass ich sogar ein Problem in der AOSP erstellt habe: code.google.com/p/android/issues/… XD
Guillem Roca
Danke für den Tipp. Zumindest hat es uns bei der Lösung des Problems geholfen. Jetzt versuchen wir herauszufinden, Option, um es Vollbild zu machen
Paresh Mayani
Du bist ein Lebensretter! Ich war absolut ahnungslos, warum ich dieses Problem hatte und immer noch ahnungslos, warum es funktionierte!
Nandu
10

Ich hatte das gleiche Problem, für das ich den Adapter von FragmentPagerAdapterzu FragmentStatePagerAdapterund getFragmentManager()im übergeordneten Fragment auf geändert habegetChildFragmentManager()

Der Grund dafür ist FragmentStatePagerAdapterhilfreich beim Speichern einer großen Anzahl von Seiten, und der mit jeder besuchten Seite verknüpfte Speicher ist geringer, da nur der gespeicherte Status des Fragments beibehalten wird, während die Seite nicht sichtbar ist. Dies reduziert den Overhead beim Umschalten zwischen den Fragmenten.

Yashaswi NP
quelle
4

Versuchen Sie setzen setOffscreenPageLimit (int limit)auf Eltern ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

Das hat bei mir wie Charme funktioniert.

In meinem Fall hatte ich Fragment TabLayoutmitViewPager.

Und noch eine ViewPagerin diesem Fragment. Das erste Mal funktioniert alles einwandfrei, aber wenn ich die Registerkarte wechsle und zurückkehre, ist ein Teil meines Fragments leer.

Rumit Patel
quelle
1
Gute Antwort. Es ist mir geholfen.
Thirumalvalavan
2

Das würde dir helfen.

    viewPager.setOffscreenPageLimit(position);
Pardeep Singh
quelle
1

Wir haben dies umgangen, indem wir die View-Pager-Elemente als Standardansichten und nicht als Fragmente erneut implementiert und den Adapter entsprechend geändert haben.

howettl
quelle
Sie können versuchen, die Funktion isViewFromObject (Ansichtsansicht, Objektobjekt) zu entfernen
Mina Samy
Es muss einen besseren Weg geben ....: / obwohl je mehr ich mich mit Android beschäftige, desto weniger ausgereift ist mir klar, dass es so ist.
StackOverflowed
1
Verschachtelte Fragmente werden nicht unterstützt , daher scheint eine Neuimplementierung mit der Standardansicht der richtige Weg zu sein.
Sylphe
Ich habe mit ähnlichen Problemen zu kämpfen. Ich habe versucht, PagerAdapter anstelle von FragmentAdapter zu verwenden, aber ich habe immer noch das gleiche Problem. Bitte hilf mir !
Gaurav Arora
Wenn Sie verschachtelte Fragmente verwenden möchten, können Sie den Adapter verwenden, den ich in dieser Antwort angegeben habe: stackoverflow.com/questions/7700226/…
Slickelito
1

Ich habe das gleiche Problem auf Xamarin Android mit einem leeren Bildschirm beim zweiten Mal bekommen. Die folgenden Einstellungen haben es für mich behoben.

viewPager.SaveFromParentEnabled = false;
Gerard
quelle
0

Sie können den Adapter auch für Fälle initialisieren, in denen dieser Fehler auftritt, wenn Ihre App minimiert und später aufgerufen wird.

@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
quelle
0

Ich hatte das gleiche, beim zweiten Aufruf des Pager-Adapters gab die untergeordnete Ansicht eine NullPointerException zurück. Und das Ändern des Adapters in FragmentStatePagerAdapter löst auch mein Problem.

Arka-57
quelle
0

Wechseln Sie FragmentPagerAdapterin FragmentStatePagerAdapter Verwendung getChildFragmentManager()anstelle vongetFragmentManager()

getChildFragmentManager()- weil laut Dokumentation ein privater FragmentManager zum Platzieren und Verwalten von Fragmenten innerhalb dieses Fragments zurückgegeben wird. In der Zwischenzeit getFragmentManager()wird der FragmentManager für die Interaktion mit Fragmenten zurückgegeben, die dieser Aktivität zugeordnet sind

Mostafa Anter
quelle
0

Klasse ViewPagerAdapter erweitert FragmentStatePagerAdapter diese Arbeit für mich versuchen Sie dies

Abdul Basit Abbasi
quelle