FragmentPagerAdapter getItem wird nicht aufgerufen

123

Ich kann das Fragment in FragmentPagerAdapter nicht wiederverwenden. Mit der Methode destroyItem () wird das Fragment gelöscht, aber immer noch nicht erneut getItem () aufgerufen. Es gibt nur 2-3 Bilder, daher verwende ich FragmentPagerAdapter anstelle von FragmentStatePagerAdapter.

public class ExamplePagerAdapter extends FragmentPagerAdapter {

    ArrayList < String > urls;
    int size = 0;
    public ExamplePagerAdapter(FragmentManager fm, ArrayList < String > res) {
        super(fm);
        urls = res;
        size = urls.size();
    }

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

    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment = new FloorPlanFragment();
        Bundle b = new Bundle();
        b.putInt("p", position);
        b.putString("image", urls.get(position));
        Log.i("image", "" + urls.get(position));
        fragment.setArguments(b);
        return fragment;
    }
}

Und in FragmentActivity,

pager.setAdapter(new ExamplePagerAdapter(getSupportFragmentManager(), res2)); 
Kanika
quelle
3
Gibt es einen bestimmten Grund, warum Sie überschrieben haben destroyItem()? Das ist nicht nötig.
CommonsWare
Zum erneuten Initialisieren verwenden Sie FragmentStatePagerAdapter. Rufen Sie auch auf, wenn Sie es überschreiben. super.destroyItem (Container, Position, Objekt);
faiziii

Antworten:

306

KISS Antwort:

Verwenden Sie einfach FragmentStatePagerAdapter anstelle von FragmentPagerAdapter .

Ich habe die Antwort erhalten. Zuerst dachte ich, diese Frage zu löschen, da ich einen sehr dummen Fehler mache, aber diese Antwort hilft jemandem, der mit dem gleichen Problem konfrontiert ist, das stattdessen FragmentPagerAdapterverwendet wird FragmentStatePagerAdapter.

Wie @BlackHatSamurai im Kommentar erwähnt:

Der Grund dafür ist, dass FragmentStatePagerAdapterals Fragmente zerstört werden, die nicht verwendet werden. FragmentPagerAdapternicht.

Kanika
quelle
Vielen Dank. Ihre Antwort hat mir sehr geholfen.
Priya
1
Ich hasse es, ein anderes Ich zu sein! post, aber yeah>. <Danke, dass du die Frage nicht gelöscht hast.
Paul Ruiz
34
Der Grund dafür ist, dass FragmentStatePagerAdapter als Fragmente zerstört wird, die nicht verwendet werden. FragmentPagerAdapter nicht.
BlackHatSamurai
3
Nur als zukünftige Referenz für diejenigen, die dies möglicherweise finden, während sie nach einem bestimmten Problem suchen, das sie haben; Lesen Sie sowohl FragmentPagerAdapter als auch FragmentStatePagerAdapter. Sie verhalten sich aus einem bestimmten Grund anders und Ihre spezifische Verwendung erfordert möglicherweise eine übereinander.
Chris Stewart
2
@najibputhawala Ich habe FragmentStatePagerAdapter verwendet, habe aber immer noch das gleiche Problem. getItem () nicht aufgerufen
sam_k
168

Die Verwendung von a FragmentStatePagerAdapterhat mein Problem nicht vollständig behoben. Dies war ein ähnliches Problem, bei dem onCreateViewim Ansichtspager keine untergeordneten Fragmente aufgerufen wurden. Ich verschachteleFragmentPagerAdapterFragment tatsächlich mein Inneres in einem anderen, daher FragmentManagerwurde das in allen geteilt und behält so Instanzen der alten Fragmente bei. Das Update bestand darin, stattdessen eine Instanz von getChildFragmentManagerdem Konstruktor von FragmentPagerAdapterin meinem Host-Fragment zuzuführen. Etwas wie...

FragmentPagerAdapter adapter = new FragmentPagerAdapter(getChildFragmentManager());

Auf die getChildFragmentManager()Methode kann über ein Fragment zugegriffen werden, und dies hat bei mir funktioniert, da sie FragmentManagerfür dieses Fragment eine private zurückgibt , insbesondere für Situationen, in denen Verschachtelungsfragmente benötigt werden. Ich hoffe, das hilft jemandem, der vielleicht das gleiche Problem hat wie ich !!

  • Denken Sie jedoch daran, dass die Verwendung getChildFragmentManager()Ihrer Mindest-API-Version mindestens erfolgen muss 17 (4.2), damit dies einen Schraubenschlüssel in Ihre Zahnräder werfen kann. Wenn Sie Fragmente aus der Support-Bibliothek v4 verwenden, sollten Sie natürlich in Ordnung sein.
Jraco11
quelle
25
Dies ist die richtige Antwort. Das Problem ist, dass die in anderen Fragmenten verschachtelten Fragmente getChildrenFragmentManager () anstelle von getFragmentManager () verwenden sollten.
Shihpeng
Vielen Dank, ich habe ewig gebraucht, um diese Antwort zu finden!
Shpongoloid
Ich stimme @shihpeng zu. Dies sollte die richtige Antwort sein.
Raymond Lukanta
Dieser war eine Lösung für mich. Vielen Dank für die Übermittlung einer Antwort
user3734429
Die Dokumente sollten dies im Durchgang wirklich hervorheben. Es ist sehr realistisch, dass ein ViewPager in ein Fragment geladen wird. Vielen Dank für die Veröffentlichung dieser Antwort.
arbeitete
7

Überschreiben long getItemId (int position)

FragmentPagerAdapterspeichert die Fragmente zwischen, die es mit erstellt getItem. Ich hatte das gleiche Problem - auch nachdem notifyDataSetChanged() getItemnicht angerufen wurde.

Dies ist eigentlich eine Funktion und kein Fehler. Sie müssen überschreiben, getItemIddamit Sie Ihre Fragmente korrekt wiederverwenden können. Da Sie Fragmente entfernen, ändern sich Ihre Positionen. Wie in den Dokumenten erwähnt:

long getItemId (int position)

Geben Sie eine eindeutige Kennung für den Artikel an der angegebenen Position zurück.

Die Standardimplementierung gibt die angegebene Position zurück. Unterklassen sollten diese Methode überschreiben, wenn sich die Positionen von Elementen ändern können.

Geben Sie einfach für jedes Fragment eine eindeutige ID ein, und fertig.

Ein Verwenden FragementStatePagerAdapteroder der Rückkehr POSITION_NONEin int getItemPosition (Object object)ist falsch. Sie erhalten kein Caching.

vedant
quelle
Dieser war die richtige Antwort. Ich musste verschiedene IDs für die Fragmente in getItemIdAND angeben, getItemPositionum zurückzugeben, POSITION_NONEWENN das Fragment entfernt werden sollte. Ich habe eine Enum-Flagge dafür. Danach getItemwird aufgerufen.
Murat Karagöz
Vielen Dank an MuratKaragöz für die +50 :)
vedant
5

Ich habe getan, was @kanika und @ Jraco11 gepostet hatten, aber ich hatte immer noch das Problem.

Nach vielen Änderungen fand ich eine, die für mich funktionierte, und meinem FragmentPagerAdapter wurde der nächste Code hinzugefügt:

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

Nach dem, was ich gelesen habe, wird getItemPosition verwendet, um den ViewPager zu benachrichtigen, ob ein Element aktualisiert werden soll oder nicht, und um Aktualisierungen zu vermeiden, wenn sich die Elemente an den sichtbaren Positionen nicht geändert haben.

Jorge Casariego
quelle
2

Es gibt zwei verschiedene Szenarien: 1.) Sie haben für jeden Pager das gleiche Layout: In diesem Fall ist es besser, wenn Sie Ihren benutzerdefinierten Adapter um PagerAdapter erweitern und ein einzelnes Layout zurückgeben.

2.) Sie haben für jeden Pager ein anderes Layout: In diesem Fall ist es besser, wenn Sie Ihren benutzerdefinierten Adapter um FragmentStatePagerAdapter erweitern und für jeden Pager unterschiedliche Fragmets zurückgeben.

Maddy
quelle
2

Methode getItem()wird nur verwendet, um neue Elemente zu erstellen. Nach der Erstellung wird diese Methode nicht mehr aufgerufen. Verwenden Sie diese Methode, wenn Sie einen Artikel benötigen, dessen Währung vom Adapter verwendet wird:

pagerAdapter.instantiateItem(viewPager, TAB_POS)
B-GangsteR
quelle
0

Ich fand heraus, dass das Festlegen eines Listeners im Registerkartenlayout den Aufruf dieses Listeners verhinderte, wahrscheinlich weil nur Platz für einen Listener tabLayout.setOnTabSelectedListeneranstelle eines Arrays von Listenern vorhanden ist.

Oliver Dixon
quelle