Die Hauptantwort basiert auf einem Namen, der vom Framework generiert wird. Wenn sich das jemals ändert, wird es nicht mehr funktionieren.
Was ist mit dieser übergeordneten Lösung instantiateItem()
und destroyItem()
Ihrer Fragment(State)PagerAdapter
:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
Dies scheint für mich zu funktionieren, wenn es um verfügbare Fragmente geht. Fragmente, die noch nicht instanziiert wurden, geben beim Aufruf null zurück getRegisteredFragment
. Aber ich habe dies hauptsächlich verwendet, um den Strom Fragment
aus dem ViewPager
: herauszuholen, adapater.getRegisteredFragment(viewPager.getCurrentItem())
und dies wird nicht zurückkehren null
.
Mir sind keine weiteren Nachteile dieser Lösung bekannt. Wenn es welche gibt, würde ich gerne wissen.
Straßen von Boston
quelle
Fragment
in einWeakReference
zu wickeln, um zu garantieren, dass Sie nicht verhindern, dass ein zerstörtes Fragment Müll sammelt?MyPagerAdapter
aufgrund des Lebenszyklus zerstört wird (dh sich dreht) und nichtregisterdFragments
verloren geht? Muss dieActivity
/Fragment
usingMyPagerAdapter
es speichernonSaveInstanceState
und dann mit der neuenFragmentManager
Referenz aktualisieren ?getItem
beim Drehen nicht erneut aufgerufen wird (für bereits erstellte Frags), da derFragmentManager
Status desFragments
im Pager enthaltenen Frags wiederhergestellt wird . WenninstantiateItem
bei jederFragment
Wiederherstellung aufgerufen wird, ist diese Lösung tatsächlich sicherer und zukunftssicherer als meine oder die akzeptierte Antwort. Ich werde darüber nachdenken, es selbst zu versuchen.Um Fragmente aus einem ViewPager zu holen, gibt es hier und in anderen verwandten SO-Threads / Blogs viele Antworten. Jeder, den ich gesehen habe, ist kaputt und scheint im Allgemeinen in einen der beiden unten aufgeführten Typen zu fallen. Es gibt einige andere gültige Lösungen, wenn Sie nur das aktuelle Fragment abrufen möchten, wie diese andere Antwort in diesem Thread.
Bei Verwendung
FragmentPagerAdapter
siehe unten. Bei der Verwendung vonFragmentStatePagerAdapter
seinem Wert bei der Suche dieses . Das Abrufen von Indizes, die nicht die aktuellen in einem FragmentStateAdapter sind, ist nicht so nützlich, da diese von Natur aus vollständig abgerissen werden und nicht mehr im Blickfeld / außerhalb der Grenzen von offScreenLimit liegen.DIE UNGLÜCKLICHEN WEGE
Falsch: Pflegen Sie Ihre eigene interne Liste von Fragmenten, die zum Zeitpunkt des Aufrufs hinzugefügt
FragmentPagerAdapter.getItem()
wirdSparseArray
oderMap
getItem
es nur beim ersten Scrollen einer Seite genannt wird (oder erhalten wird, wenn IhreViewPager.setOffscreenPageLimit(x)
> 0 ist)ViewPager
, wird das interne gelöscht , wenn das HostingActivity
/ beendetFragment
oder neu gestartetSpaseArray
wird, wenn die benutzerdefinierte FragmentPagerActivity neu erstellt wird, aber hinter den Kulissen ViewPagers interne Fragmente werden neu erstellt, undgetItem
werden nicht für einen des Indizes bezeichnet werden, so dass die Fähigkeit , ein Fragment aus dem Index erhalten wird für immer verloren sein. Sie können durch die Einsparung aus der Rechnung zu tragen und die Wiederherstellung dieser Fragmentverweise überFragmentManager.getFragment()
undputFragment
aber das beginnt chaotisch IMHO zu bekommen.Falsch: Erstellen Sie Ihre eigene Tag-ID, die mit der unter der Haube verwendeten übereinstimmt,
FragmentPagerAdapter
und rufen Sie damit die Seitenfragmente aus derFragmentManager
ViewPager
das könnte jederzeit oder für jede Betriebssystemversion ändern.Die für diese Lösung neu erstellte Methode ist
EIN GLÜCKLICHER WEG:
ViewPager.instantiateItem()
Ein ähnlicher Ansatz wie
getItem()
oben, jedoch ohne Unterbrechung des Lebenszyklus, besteht darin, sich anzuschließen,instantiateItem()
anstatt,getItem()
wie der erstere jedes Mal aufgerufen wird, wenn dieser Index erstellt wird / auf den zugegriffen wird. Siehe diese AntwortEIN GLÜCKLICHER WEG: Konstruieren Sie Ihren eigenen
FragmentViewPager
Erstellen Sie Ihre eigene
FragmentViewPager
Klasse aus der Quelle der neuesten Support-Bibliothek und ändern Sie die Methode, die intern zum Generieren der Fragment-Tags verwendet wird. Sie können es durch das folgende ersetzen. Dies hat den Vorteil, dass Sie wissen, dass sich die Tag-Erstellung niemals ändern wird und Sie sich nicht auf eine private API / Methode verlassen, was immer gefährlich ist.Wenn Sie dann, wie das Dokument sagt, ein für einen Index verwendetes Fragment abrufen möchten, rufen Sie einfach so etwas wie diese Methode auf (die Sie in die benutzerdefinierte
FragmentPagerAdapter
oder eine Unterklasse einfügen können ), wobei Sie sich bewusst sind, dass das Ergebnis möglicherweise null ist, wenn getItem noch nicht aufgerufen wurde Diese Seite wurde noch nicht erstellt.Dies ist eine einfache Lösung und löst die Probleme in den beiden anderen Lösungen, die überall im Web zu finden sind
quelle
instantiateItem()
wenn Sie auf ein Fragment zugreifen möchten, das noch nicht besucht wurde, nachdem ein Lebenszyklusereignis stattgefunden hat und das vor dem Lebenszyklusereignis besucht wurde. Ein kleiner Unterschied, den ich kenne, der jedoch zu einem subtilen Fehler in meinem Programm geführt hat, weshalb ich mich damit befasse.getItemId(pos)
drinnenFragmentStatePagerAdapter
Fügen Sie Ihrem FragmentPagerAdapter die nächsten Methoden hinzu:
getActiveFragment (0) muss funktionieren.
Hier ist die in ViewPager implementierte Lösung https://gist.github.com/jacek-marchwicki/d6320ba9a910c514424d . Wenn etwas fehlschlägt, wird ein gutes Absturzprotokoll angezeigt.
quelle
Eine weitere einfache Lösung:
quelle
setPrimaryItem()
es heißt, nachdemViewPager.OnPageChangeListener#onPageSelected()
ich es nicht verwenden kann :-(Ich weiß, dass dies einige Antworten hat, aber vielleicht hilft dies jemandem. Ich habe eine relativ einfache Lösung verwendet, als ich eine
Fragment
von meiner bekommen mussteViewPager
. In IhremActivity
oder inFragment
derViewPager
Hand können Sie diesen Code verwenden, um alleFragment
darin enthaltenen Daten zu durchlaufen .Wenn Sie die Position Ihres
Fragment
in der kennenViewPager
, können Sie einfach anrufengetItem(knownPosition)
.Wenn Sie die Position Ihres
Fragment
in nicht kennenViewPager
, können Sie Ihre KinderFragments
eine Schnittstelle mit einer Methode wie implementieren lassengetUniqueId()
und diese verwenden, um sie zu unterscheiden. Oder Sie können alle durchlaufenFragments
und den Klassentyp überprüfen, zif(viewPagerFragment instanceof FragmentClassYouWant)
!!! BEARBEITEN !!!
Ich habe festgestellt, dass
getItem
nur von a aufgerufen wird,FragmentPagerAdapter
wenn jedesFragment
beim ersten Mal erstelltFragments
werden muss. Danach scheint es, dass die mit dem recycelt werdenFragmentManager
. Auf diese WeiseFragmentPagerAdapter
erstellen viele Implementierungen neueFragment
s ingetItem
. Mit meiner obigen Methode bedeutet dies, dass wir beiFragment
jedemgetItem
Aufruf neue s erstellen, wenn wir alle Elemente in derFragmentPagerAdapter
. Aus diesem Grund habe ich einen besseren Ansatz gefunden, indemFragmentManager
ichFragment
stattdessen den verwendet habe , um jeden zu erhalten (unter Verwendung der akzeptierten Antwort). Dies ist eine vollständigere Lösung und hat für mich gut funktioniert.Und Sie werden diese Methode brauchen.
quelle
ViewPager
selbst setzt diese Tags. Diese Lösung ist fragil, da sie darauf beruht, die "versteckte" Namenskonvention der zu kennenViewPager
. Die Antwort von Streets of Boston ist eine viel umfassendere Lösung, die ich jetzt in meinem Projekt verwende (anstelle dieses Ansatzes).In meinem Fall hat keine der oben genannten Lösungen funktioniert.
Da ich jedoch den Child Fragment Manager in einem Fragment verwende, wurde Folgendes verwendet:
Fragment f = getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
Dies funktioniert nur, wenn Ihre Fragmente im Manager dem Viewpager-Element entsprechen.
quelle
quelle
Ich habe es geschafft, indem ich zuerst eine Liste aller Fragmente (
List<Fragment> fragments;
) erstellt habe, die ich verwenden wollte, und sie dann dem Pager hinzugefügt habe, um die Handhabung des aktuell angezeigten Fragments zu vereinfachen.So:
also dann kann dies genannt werden:
Also könnte ich es in eine if-Anweisung stecken, die nur ausgeführt wird, wenn es sich auf dem richtigen Fragment befindet
Aber das ist nur mein Hack-and-Slash-Ansatz, aber er hat bei mir funktioniert. Ich verwende ihn, um relevante Änderungen an meinem aktuell angezeigten Fragment vorzunehmen, wenn die Zurück-Taste gedrückt wird.
quelle
Dies basiert auf der obigen Antwort von Steven. Dies gibt die tatsächliche Instanz des Fragments zurück, das bereits an die übergeordnete Aktivität angehängt ist.
quelle
Ich konnte keinen einfachen, sauberen Weg finden, dies zu tun. Das ViewPager-Widget ist jedoch nur eine weitere ViewGroup, die Ihre Fragmente hostet. Der ViewPager hat diese Fragmente als unmittelbare untergeordnete Elemente. Sie können sie also einfach durchlaufen (mit .getChildCount () und .getChildAt ()) und prüfen, ob die gesuchte Fragmentinstanz derzeit in den ViewPager geladen ist, und einen Verweis darauf abrufen. Sie könnten beispielsweise ein statisches eindeutiges ID-Feld verwenden, um die Fragmente voneinander zu unterscheiden.
Beachten Sie, dass der ViewPager das gesuchte Fragment möglicherweise nicht geladen hat, da es sich um einen Virtualisierungscontainer wie ListView handelt.
quelle
FragmentPagerAdapter ist die Factory der Fragmente. Verwenden Sie Folgendes, um ein Fragment anhand seiner Position zu finden, wenn es sich noch im Speicher befindet:
Beispielcode für die v4-Support-API.
quelle
Sie müssen zu einem späteren Zeitpunkt keine
getItem()
andere Methode aufrufen , um die Referenz einesFragment
gehosteten Inners abzurufenViewPager
. Wenn Sie einige darin enthaltene Daten aktualisieren möchten,Fragment
verwenden Sie diesen Ansatz: ViewPager dynamisch aktualisieren?Der Schlüssel besteht darin, neue Daten festzulegen
Adaper
und aufzurufen,notifyDataSetChanged()
die wiederum aufrufengetItemPosition()
, Ihnen eine Referenz von Ihnen übergebenFragment
und Ihnen die Möglichkeit geben, diese zu aktualisieren. Bei allen anderen Möglichkeiten müssen Sie sich auf sich selbst oder einen anderen Hack beziehen, was keine gute Lösung ist.quelle
getItemPosition()
ist eine Methode in Ihrem Adapter. Sie werden es nicht direkt anrufen. Sie haben eine Referenz Ihres Adapters, also rufen Sie an,adapter.notifyDataSetChanged()
die wiederumgetItemPosition()
Ihren Adapter aufruft, indem Sie die Referenz IhresFragment
s übergeben. Eine vollständige Implementierung in Aktion finden Sie hier stackoverflow.com/questions/19891828/…Fragment
um eine Referenz zu aktualisieren, aber wie man eine Referenz erhält, ist umstritten. Andere Lösungen erhalten Referenz vonFragmentManager
einer Zeichenfolge ähnelt der Verwendung"android:switcher:"+id
oder die RückkehrPOSITION_NONE
vongetItemosition()
allen Fragmenten verursacht selbst neu zu erstellen.Muss sich
FragmentPagerAdapter
auf Ihre ViewPager-Adapterklasse erstrecken .Wenn Sie verwenden,
FragmentStatePagerAdapter
können Sie Ihre nichtFragment
anhand ihrer findenID
So verwenden Sie diese Methode: -
quelle
Hey, ich habe diese Frage hier beantwortet . Grundsätzlich müssen Sie überschreiben
Methode von FragmentStatePagerAdapter.
quelle
Beste Lösung ist es, die Erweiterung verwenden wir erstellt bei Codepfad genannt SmartFragmentStatePagerAdapter . Wenn Sie dieser Anleitung folgen, wird das Abrufen von Fragmenten und des aktuell ausgewählten Fragments aus einem ViewPager erheblich vereinfacht. Außerdem kann der Speicher der im Adapter eingebetteten Fragmente besser verwaltet werden.
quelle
Der einfachste und prägnanteste Weg. Wenn alle Ihre Fragmente in
ViewPager
verschiedenen Klassen sind, können Sie sie wie folgt abrufen und unterscheiden:quelle
Ich habe dies einfach mit einem etwas anderen Ansatz implementiert.
Meine benutzerdefinierte FragmentAdapter.getItem-Methode hat nicht neues MyFragment () zurückgegeben, sondern die Instanz von MyFragment, die im FragmentAdapter-Konstruktor erstellt wurde.
In meiner Aktivität habe ich dann das Fragment vom Adapter erhalten, überprüft, ob es eine Instanz des benötigten Fragments ist, und dann die erforderlichen Methoden umgewandelt und verwendet.
quelle
Erstellen Sie eine ganzzahlige Ressourcen-ID in /values/integers.xml
Dann in PagerAdapter getItem Funktion:
Schreiben Sie dann in der Aktivität diese Funktion, um die Fragmentreferenz zu erhalten:
Rufen Sie die obige Funktion auf, um die Fragmentreferenz abzurufen, und wandeln Sie sie dann in Ihr benutzerdefiniertes Fragment um:
quelle
Einfache Möglichkeit, Fragmente im Fragment-Manager zu durchlaufen. Suchen Sie den Viewpager mit dem Argument für die Abschnittsposition in der öffentlichen statischen PlaceholderFragment newInstance (int sectionNumber) .
quelle
Im Fragment
In FragmentActivity
quelle
In TabLayout gibt es mehrere Registerkarten für Fragment. Sie können das Fragment anhand des Index des Fragments anhand des Tags finden.
Zum Beispiel. Der Index für Fragment1 ist 0, also übergeben Sie in der
findFragmentByTag()
Methode das Tag für den Viewpager. Nachdem Sie fragmentTransaction verwendet haben, das Sie hinzufügen können, ersetzen Sie das Fragment.String tag = "android:switcher:" + R.id.viewPager + ":" + 0; Fragment1 f = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
quelle
Ok für den Adapter
FragmentStatePagerAdapter
finanziere ich eine Lösung:in Ihrer FragmentActivity:
und erstellen Sie eine Methode in Ihrer Klasse FragmentActivity - Damit Sie mit dieser Methode auf Ihr Fragment zugreifen können, müssen Sie ihm nur die Position des gewünschten Fragments geben:
in Ihrem Adapter:
quelle
index
in - Adapter ist der Ort des Fragments wie Sie hinzugefügtfragment1
zuerst so retreivefragment1
Passindex
als 0 und so weiter für Ruhequelle