Rufen Sie ein Fragment aus einem ViewPager ab

248

Ich verwende a ViewPagerzusammen mit a FragmentStatePagerAdapter, um drei verschiedene Fragmente zu hosten:

  • [Fragment1]
  • [Fragment2]
  • [Fragment3]

Wenn ich Fragment1von der ViewPagerin die kommen will FragmentActivity.

Was ist das Problem und wie behebe ich es?

Qun Qin
quelle

Antworten:

504

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 Fragmentaus 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
41
Dies ist die beste Lösung, die ich mir vorstellen kann. Der einzige Vorschlag wäre, das vielleicht Fragmentin ein WeakReferencezu wickeln, um zu garantieren, dass Sie nicht verhindern, dass ein zerstörtes Fragment Müll sammelt?
Alex Lockwood
7
Was passiert, wenn es MyPagerAdapteraufgrund des Lebenszyklus zerstört wird (dh sich dreht) und nicht registerdFragmentsverloren geht? Muss die Activity/ Fragmentusing MyPagerAdapteres speichern onSaveInstanceStateund dann mit der neuen FragmentManagerReferenz aktualisieren ?
Steven Byle
10
Wenn ich mich nicht irre (und Sie sollten dies überprüfen), wird die Methode getItem nicht aufgerufen - wie Sie wissen -, aber die Methode instantiateItem wird für jedes Fragment aufgerufen, das nach einer Rotation vom Framework wiederhergestellt wird.
Straßen von Boston
6
Ja, ich habe überprüft, dass getItembeim Drehen nicht erneut aufgerufen wird (für bereits erstellte Frags), da der FragmentManagerStatus des Fragmentsim Pager enthaltenen Frags wiederhergestellt wird . Wenn instantiateItembei jeder FragmentWiederherstellung 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.
Steven Byle
6
@ Dori Ich breche es nicht. Meine Lösung verwendet nicht das Ergebnis des Aufrufs 'getItem ()'. Stattdessen wird das Ergebnis des Aufrufs 'instantiateItem ()' verwendet. Der Lebenszyklus des Fragments wird nicht unterbrochen, da das gespeicherte Fragment beim Aufruf von 'destroyItem ()' aus dem Sparse-Array entfernt wird.
Straßen von Boston
85

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 FragmentPagerAdaptersiehe unten. Bei der Verwendung von FragmentStatePagerAdapterseinem 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()wird

  • Normalerweise mit einem SparseArrayoderMap
  • Keines der vielen Beispiele, die ich gesehen habe, erklärt Lebenszyklusereignisse, daher ist diese Lösung fragil. Wie getItemes nur beim ersten Scrollen einer Seite genannt wird (oder erhalten wird, wenn Ihre ViewPager.setOffscreenPageLimit(x)> 0 ist) ViewPager, wird das interne gelöscht , wenn das Hosting Activity/ beendet Fragmentoder neu gestartet SpaseArraywird, wenn die benutzerdefinierte FragmentPagerActivity neu erstellt wird, aber hinter den Kulissen ViewPagers interne Fragmente werden neu erstellt, und getItemwerden 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 über FragmentManager.getFragment()und putFragmentaber 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

  • Das ist besser so sehr , wie es mit dem Verlierer-Fragmente Verweisen Problem in der ersten Innen-Array - Lösung meistert, sondern wie zu Recht in den Antworten oben und an anderer Stelle im Netz hingewiesen - es fühlt sich hacky als eine private Methode intern ViewPagerdas könnte jederzeit oder für jede Betriebssystemversion ändern.

Die für diese Lösung neu erstellte Methode ist

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

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 Antwort

EIN GLÜCKLICHER WEG: Konstruieren Sie Ihren eigenen FragmentViewPager

Erstellen Sie Ihre eigene FragmentViewPagerKlasse 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.

/**
 * @param containerViewId the ViewPager this adapter is being supplied to
 * @param id pass in getItemId(position) as this is whats used internally in this class
 * @return the tag used for this pages fragment
 */
public static String makeFragmentName(int containerViewId, long id) {
    return "android:switcher:" + containerViewId + ":" + id;
}

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 FragmentPagerAdapteroder 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.

/**
 * @return may return null if the fragment has not been instantiated yet for that position - this depends on if the fragment has been viewed
 * yet OR is a sibling covered by {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)}. Can use this to call methods on
 * the current positions fragment.
 */
public @Nullable Fragment getFragmentForPosition(int position)
{
    String tag = makeFragmentName(mViewPager.getId(), getItemId(position));
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
    return fragment;
}

Dies ist eine einfache Lösung und löst die Probleme in den beiden anderen Lösungen, die überall im Web zu finden sind

Dori
quelle
6
Dies funktioniert, erfordert jedoch das Kopieren der ViewPager-Klasse in Ihren eigenen Quellcode. Wenn Sie sich auf das 'instantiateItem ()' und 'destroyItem ()' des Pager-Adapters eines ViewPager verlassen, funktioniert dies und berücksichtigt die Lebenszyklen der Fragmente (diese beiden Methoden werden auch aufgerufen, wenn Fragmente aus einem Status einer gespeicherten Instanz erstellt werden). Sie haben Recht, dass es keine gute Idee ist, sich auf den Aufruf von 'getItem ()' zu verlassen, und die Verwendung privater APIs auch nicht.
Straßen von Boston
+1 Ich stimme zu, dass dies auch eine Lösung ist und habe oben bearbeitet. Der einzige Unterschied besteht darin, dass das Obige in einem weiteren Anwendungsfall funktioniert, nämlich 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.
Dori
Wenn setOffscreenPageLimit = 1 (Standard) ist, beginnt FragmentStatePageAdapter, Fragmente beim Zugriff auf Ansichtsseiten in den Speicher und aus dem Speicher zu tauschen. Durch einen Aufruf von getItem () wird dann eine neue Instanz von überarbeiteten Seiten / Fragmenten erstellt. Gibt es bei einem solchen erneuten Besuch eine Möglichkeit, das System anzuweisen, zuvor erstellte Instanzen fortzusetzen, anstatt eine neue zu erstellen?
Carl
Wenn es außerhalb des Seitenlimits liegt, muss ein neues erstellt werden - aber im gespeicherten Zustand. Wenn Sie die alten behalten möchten, können Sie das Seitenlimit erhöhen
Dori
@ Dori gibt es nicht getItemId(pos)drinnenFragmentStatePagerAdapter
Jemshit Iskenderov
70

Fügen Sie Ihrem FragmentPagerAdapter die nächsten Methoden hinzu:

public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return  mFragmentManager.findFragmentByTag(name);
}

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

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.

Kzotin
quelle
Vielen Dank:) . Durch habe ich es auf eine andere Weise gesiebt, die ich mit einem Handler poste, um das Fragment zu posten. Dies ist nicht sehr geeignet, aber es hat das Problem endgültig gelöst. Übrigens, du bist nett :)
Qun Qin
12
Ich habe diese Methode verwendet, aber ich glaube, sie hat nicht mehr funktioniert, als ich auf API 17 (?) Umgestiegen bin. Ich würde eine andere Methode empfehlen und es vorziehen, wenn Google einfach eine API veröffentlicht, um ein Fragment aufgrund seiner Position aus einem ViewPager abzurufen.
gcl1
Ich habe ein Problem mit dem Aufruf des zweiten Fragments, die Methode erstellt ein neues
Vasil Valchev
2
Seit einer API-Version wurde die Methode makeFragmentName in eine private statische Zeichenfolge geändert. MakeFragmentName (int viewId, lange ID) {return "android: switcher:" + viewId + ":" + id; } Die getActiveFragment-Methode sollte nun folgendermaßen aussehen (verwenden Sie getItemId anstelle der Position für das zweite Argument). Public Fragment getActiveFragment (ViewPager-Container, int-Position) {String name = makeFragmentName (container.getId (), getItemId (position)); return mFragmentManager.findFragmentByTag (Name); }
Eugene Popovich
1
Es funktioniert wirklich, aber es ist wirklich gefährlich, weil es sich auf die innere Implementierung des View-Pagers bezieht und wenn Google die Implementierung ändert (und sie können), werden schlimme Dinge passieren. Ich hoffe wirklich, dass Goole es zur Verfügung stellt, um das Live-Fragment zu bekommen
Shem
38

Eine weitere einfache Lösung:

    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }
Mindphaser
quelle
1
Dies scheint perfekt für meine aktuellen Fragmentbedürfnisse zu sein.
danny117
Wenn Sie nur das aktuell ausgewählte Fragment abrufen müssen, ist dies alles, was Sie benötigen - die Methode setPrimaryItem wird beim Anhängen und bei jeder Aktualisierung des internen Satzes des Fragments als aktuelles Element festgelegt.
Graeme
1
Das klingt nach einer schönen Lösung, aber wie setPrimaryItem()es heißt, nachdem ViewPager.OnPageChangeListener#onPageSelected() ich es nicht verwenden kann :-(
hardysim
21

Ich weiß, dass dies einige Antworten hat, aber vielleicht hilft dies jemandem. Ich habe eine relativ einfache Lösung verwendet, als ich eine Fragmentvon meiner bekommen musste ViewPager. In Ihrem Activityoder in Fragmentder ViewPagerHand können Sie diesen Code verwenden, um alle Fragmentdarin enthaltenen Daten zu durchlaufen .

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    Fragment viewPagerFragment = fragmentPagerAdapter.getItem(i);
    if(viewPagerFragment != null) {
        // Do something with your Fragment
        // Check viewPagerFragment.isResumed() if you intend on interacting with any views.
    }
}
  • Wenn Sie die Position Ihres Fragmentin der kennen ViewPager, können Sie einfach anrufen getItem(knownPosition).

  • Wenn Sie die Position Ihres Fragmentin nicht kennen ViewPager, können Sie Ihre Kinder Fragmentseine Schnittstelle mit einer Methode wie implementieren lassen getUniqueId()und diese verwenden, um sie zu unterscheiden. Oder Sie können alle durchlaufen Fragmentsund den Klassentyp überprüfen, zif(viewPagerFragment instanceof FragmentClassYouWant)

!!! BEARBEITEN !!!

Ich habe festgestellt, dass getItemnur von a aufgerufen wird, FragmentPagerAdapterwenn jedes Fragmentbeim ersten Mal erstellt Fragmentswerden muss. Danach scheint es, dass die mit dem recycelt werden FragmentManager. Auf diese Weise FragmentPagerAdaptererstellen viele Implementierungen neue Fragment s in getItem. Mit meiner obigen Methode bedeutet dies, dass wir bei Fragmentjedem getItemAufruf neue s erstellen, wenn wir alle Elemente in der FragmentPagerAdapter. Aus diesem Grund habe ich einen besseren Ansatz gefunden, indem FragmentManagerich Fragmentstattdessen 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.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {
    String name = makeFragmentName(mViewPager.getId(), i);
    Fragment viewPagerFragment = getChildFragmentManager().findFragmentByTag(name);
    // OR Fragment viewPagerFragment = getFragmentManager().findFragmentByTag(name);
    if(viewPagerFragment != null) {

        // Do something with your Fragment
        if (viewPagerFragment.isResumed()) {
            // Interact with any views/data that must be alive
        }
        else {
            // Flag something for update later, when this viewPagerFragment
            // returns to onResume
        }
    }
}

Und Sie werden diese Methode brauchen.

private static String makeFragmentName(int viewId, int position) {
    return "android:switcher:" + viewId + ":" + position;
}
Steven Byle
quelle
1
Sie finden nurFragmentByTag (), aber wo können wir die TAG mit Fragment setzen?
VinceStyling
@vince Das ViewPagerselbst setzt diese Tags. Diese Lösung ist fragil, da sie darauf beruht, die "versteckte" Namenskonvention der zu kennen ViewPager. Die Antwort von Streets of Boston ist eine viel umfassendere Lösung, die ich jetzt in meinem Projekt verwende (anstelle dieses Ansatzes).
Steven Byle
Das funktioniert super! Ich habe jedoch die Bedingung "if (viewPagerFragment.isResumed ())" entfernt, da ich meine ListFragment-Seiten außerhalb des Bildschirms aktualisieren muss. Wenn der Benutzer dann zur ListFragment-Seite zurückkehrt, wird alles mit den neuen Daten aktualisiert.
JDJ
10

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.

Veedka
quelle
Dies ist die perfekte Antwort, um alte Fragmente aus dem View Pager zu erhalten, wenn Aktivität oder Fragment neu erstellt werden.
Smeet
7

Um das aktuelle sichtbare Fragment von ViewPager abzurufen . Ich benutze diese einfache Aussage und sie funktioniert gut.

      public Fragment getFragmentFromViewpager()  
      {
         return ((Fragment) (mAdapter.instantiateItem(mViewPager, mViewPager.getCurrentItem())));
      }
Zar E Ahmer
quelle
3

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:

@Override
onCreate(){
    //initialise the list of fragments
    fragments = new Vector<Fragment>();

    //fill up the list with out fragments
    fragments.add(Fragment.instantiate(this, MainFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, MenuFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, StoresFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
    fragments.add(Fragment.instantiate(this, ContactFragment.class.getName()));


    //Set up the pager
    pager = (ViewPager)findViewById(R.id.pager);
    pager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(), fragments));
    pager.setOffscreenPageLimit(4);
}

also dann kann dies genannt werden:

public Fragment getFragment(ViewPager pager){   
    Fragment theFragment = fragments.get(pager.getCurrentItem());
    return theFragment;
}

Also könnte ich es in eine if-Anweisung stecken, die nur ausgeführt wird, wenn es sich auf dem richtigen Fragment befindet

Fragment tempFragment = getFragment();
if(tempFragment == MyFragmentNo2.class){
    MyFragmentNo2 theFrag = (MyFragmentNo2) tempFragment;
    //then you can do whatever with the fragment
    theFrag.costomFunction();
}

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.

Russell Cargill
quelle
1
beste Antwort für mich
Sonu Kumar
3

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.

FragmentPagerAdapter fragmentPagerAdapter = (FragmentPagerAdapter) mViewPager.getAdapter();
    for(int i = 0; i < fragmentPagerAdapter.getCount(); i++) {

        Fragment viewPagerFragment = (Fragment) mViewPager.getAdapter().instantiateItem(mViewPager, i);
        if(viewPagerFragment != null && viewPagerFragment.isAdded()) {

            if (viewPagerFragment instanceof FragmentOne){
                FragmentOne oneFragment = (FragmentOne) viewPagerFragment;
                if (oneFragment != null){
                    oneFragment.update(); // your custom method
                }
            } else if (viewPagerFragment instanceof FragmentTwo){
                FragmentTwo twoFragment = (FragmentTwo) viewPagerFragment;

                if (twoFragment != null){
                    twoFragment.update(); // your custom method
                }
            }
        }
    }
Orangenbaum
quelle
2

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.

Zsombor Erdődy-Nagy
quelle
1
Vielen Dank für Ihre Antwort. Ich rufe sie mit adpter.getItem () ab. Ich bin ein Neuling in der Android-Programmierung. Ich schätze dich sehr. Jetzt kann ich das ListFragment abrufen und möchte footerView hinzufügen. Während ich dies in meiner Aktivität mache, druckt der Logcat: "java.lang.IllegalStateException: Inhaltsansicht noch nicht erstellt." Ich weiß warum, aber ich habe Schwierigkeiten beim Umgang damit.
Qun Qin
1
FragmentActivity haben onAttachFragment () -Methode, dosieren diese Arbeit für ViewPager mit Fragmentinhalt?
Vasil Valchev
2

FragmentPagerAdapter ist die Factory der Fragmente. Verwenden Sie Folgendes, um ein Fragment anhand seiner Position zu finden, wenn es sich noch im Speicher befindet:

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

Beispielcode für die v4-Support-API.

Daniel De León
quelle
In onresume () wird null zurückgegeben. Irgendeine Idee warum und Hacke, um es zu reparieren?
scheinbar
2

Sie müssen zu einem späteren Zeitpunkt keinegetItem() andere Methode aufrufen , um die Referenz eines Fragmentgehosteten Inners abzurufen ViewPager. Wenn Sie einige darin enthaltene Daten aktualisieren möchten, Fragmentverwenden Sie diesen Ansatz: ViewPager dynamisch aktualisieren?

Der Schlüssel besteht darin, neue Daten festzulegen Adaperund aufzurufen, notifyDataSetChanged()die wiederum aufrufen getItemPosition(), Ihnen eine Referenz von Ihnen übergeben Fragmentund 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.

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(xyzData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}
M-WaJeEh
quelle
Ich verstehe hier nicht, Sie benötigen eine Referenz eines Fragments, um getItemPosition () zu verwenden, also können Sie getItemPosition genauso gut nicht verwenden, oder?
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 wiederum getItemPosition()Ihren Adapter aufruft, indem Sie die Referenz Ihres Fragments übergeben. Eine vollständige Implementierung in Aktion finden Sie hier stackoverflow.com/questions/19891828/…
M-WaJeEh
Ich habe das durchgelesen und verstehe es immer noch nicht. Sie brauchen immer noch einen direkten Verweis auf diese Fragmente, um gegen sie zu telefonieren, oder? Sie erwähnen das als Hack, aber ich sehe keine Alternative; adapter.getItem (i) wird offensichtlich nicht funktionieren.
2
Ok, ich habe meine Antwort aktualisiert, um mehr zu klären. Natürlich wird eine Referenz benötigt, Fragmentum eine Referenz zu aktualisieren, aber wie man eine Referenz erhält, ist umstritten. Andere Lösungen erhalten Referenz von FragmentManagereiner Zeichenfolge ähnelt der Verwendung "android:switcher:"+idoder die Rückkehr POSITION_NONEvon getItemosition()allen Fragmenten verursacht selbst neu zu erstellen.
M-WaJeEh
Danke, das macht viel mehr Sinn und passt zu meiner Erfahrung (also mache ich vielleicht nichts falsch, ha).
2

Muss sich FragmentPagerAdapterauf Ihre ViewPager-Adapterklasse erstrecken .
Wenn Sie verwenden, FragmentStatePagerAdapterkönnen Sie Ihre nicht Fragmentanhand ihrer findenID

public static String makeFragmentName(int viewPagerId, int index) {
  return "android:switcher:" + viewPagerId + ":" + index;
}

So verwenden Sie diese Methode: -

Fragment mFragment = ((FragmentActivity) getContext()).getSupportFragmentManager().findFragmentByTag(
       AppMethodUtils.makeFragmentName(mViewPager.getId(), i)
);
InterestViewFragment newFragment = (InterestViewFragment) mFragment;
mahesh_babariya
quelle
2

Hey, ich habe diese Frage hier beantwortet . Grundsätzlich müssen Sie überschreiben

öffentliches Objekt instantiateItem (ViewGroup-Container, int-Position)

Methode von FragmentStatePagerAdapter.

Utkarsh Saxena
quelle
1

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.

Nathan
quelle
0

Der einfachste und prägnanteste Weg. Wenn alle Ihre Fragmente in ViewPagerverschiedenen Klassen sind, können Sie sie wie folgt abrufen und unterscheiden:

public class MyActivity extends Activity
{

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        if (fragment.getClass() == MyFragment.class) {
            mMyFragment = (MyFragment) fragment;
        }
    }

}
riwnodennyk
quelle
Dies ist auch falsch, da bei Verwendung des ViewPager mehrere Fragmente angehängt werden. Es gibt das aktuelle Seitenfragment und eines links und eines rechts. Auf diese Weise kann der Benutzer zwischen ihnen wechseln, ohne sie erst initialisieren zu müssen, wenn der Benutzer sie erreicht.
Android-Entwickler
0

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.

lxknvlk
quelle
0

Erstellen Sie eine ganzzahlige Ressourcen-ID in /values/integers.xml

<integer name="page1">1</integer>
<integer name="page2">2</integer>
<integer name="page3">3</integer>

Dann in PagerAdapter getItem Funktion:

public Fragment getItem(int position) {

        Fragment fragment = null;

        if (position == 0) {
            fragment = FragmentOne.newInstance();
            mViewPager.setTag(R.integer.page1,fragment);

        }
        else if (position == 1) {

            fragment = FragmentTwo.newInstance();
            mViewPager.setTag(R.integer.page2,fragment);

        } else if (position == 2) {

            fragment = FragmentThree.newInstance();
            mViewPager.setTag(R.integer.page3,fragment);

        }

        return fragment;
        }

Schreiben Sie dann in der Aktivität diese Funktion, um die Fragmentreferenz zu erhalten:

private Fragment getFragmentByPosition(int position) {
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = (Fragment) mViewPager.getTag(R.integer.page1);
            break;

        case 1:

            fragment = (Fragment) mViewPager.getTag(R.integer.page2);
            break;

        case 2:
            fragment = (Fragment) mViewPager.getTag(R.integer.page3);
            break;
            }

            return fragment;
    }

Rufen Sie die obige Funktion auf, um die Fragmentreferenz abzurufen, und wandeln Sie sie dann in Ihr benutzerdefiniertes Fragment um:

Fragment fragment = getFragmentByPosition(position);

        if (fragment != null) {
                    FragmentOne fragmentOne = (FragmentOne) fragment;
                    }
user2574090
quelle
0

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) .

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.id.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}
Evgeny
quelle
0

Im Fragment

public int getArgument(){
   return mPage;
{
public void update(){

}

In FragmentActivity

List<Fragment> fragments = getSupportFragmentManager().getFragments();
for(Fragment f:fragments){
    if((f instanceof PageFragment)&&(!f.isDetached())){
          PageFragment pf = (PageFragment)f;   
          if(pf.getArgument()==pager.getCurrentItem())pf.update();
    }
}
Mark Zhuravlyov
quelle
0

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);

SUMIT MONAPARA
quelle
-1

Ok für den Adapter FragmentStatePagerAdapter finanziere ich eine Lösung:

in Ihrer FragmentActivity:

ActionBar mActionBar = getSupportActionBar(); 
mActionBar.addTab(mActionBar.newTab().setText("TAB1").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment1.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB2").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment2.class.getName())));
mActionBar.addTab(mActionBar.newTab().setText("TAB3").setTabListener(this).setTag(Fragment.instantiate(this, MyFragment3.class.getName())));

viewPager = (STViewPager) super.findViewById(R.id.viewpager);
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), mActionBar);
viewPager.setAdapter(this.mPagerAdapter);

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:

public Fragment getActiveFragment(int position) {
String name = MyPagerAdapter.makeFragmentName(position);
return getSupportFragmentManager().findFragmentByTag(name);
}

in Ihrem Adapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {

private final ActionBar actionBar;
private final FragmentManager fragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager, com.actionbarsherlock.app.ActionBarActionBar mActionBar) {super(fragmentManager);
this.actionBar = mActionBar;
this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
getSupportFragmentManager().beginTransaction().add(mTchatDetailsFragment, makeFragmentName(position)).commit();
return (Fragment)this.actionBar.getTabAt(position);
}

@Override
public int getCount() {
return this.actionBar.getTabCount();
}

@Override
public CharSequence getPageTitle(int position) {
return this.actionBar.getTabAt(position).getText();
}

private static String makeFragmentName(int viewId, int index) {
return "android:fragment:" + index;
}

}
Douarbou
quelle
-1
Fragment yourFragment = yourviewpageradapter.getItem(int index);

indexin - Adapter ist der Ort des Fragments wie Sie hinzugefügt fragment1zuerst so retreive fragment1Pass indexals 0 und so weiter für Ruhe

Vishnu Prasad
quelle