Ich kann den Inhalt in ViewPager nicht aktualisieren.
Was ist die korrekte Verwendung der Methoden instantiateItem () und getItem () in der FragmentPagerAdapter-Klasse?
Ich habe nur getItem () verwendet, um meine Fragmente zu instanziieren und zurückzugeben:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
Das hat gut funktioniert. Außer ich kann den Inhalt nicht ändern.
Also fand ich Folgendes : ViewPager PagerAdapter aktualisiert die Ansicht nicht
"Mein Ansatz ist es, die setTag () -Methode für jede instanziierte Ansicht in der instantiateItem () -Methode zu verwenden."
Jetzt möchte ich instantiateItem () implementieren, um dies zu tun. Aber ich weiß nicht, was ich zurückgeben muss (der Typ ist Object) und wie ist die Beziehung zu getItem (int position)?
Ich habe die Referenz gelesen :
public abstract Fragment getItem (int position)
Gibt das Fragment zurück, das einer bestimmten Position zugeordnet ist.
public Object instantiateItem (ViewGroup-Container, int-Position)
Erstellen Sie die Seite für die angegebene Position. Der Adapter ist für das Hinzufügen der Ansicht zu dem hier angegebenen Container verantwortlich, muss jedoch nur sicherstellen, dass dies bis zum Zeitpunkt der Rückkehr von finishUpdate (ViewGroup) erfolgt. Parameter
container Die enthaltende Ansicht, in der die Seite angezeigt wird. position Die zu instanziierende Seitenposition.
Kehrt zurück
Gibt ein Objekt zurück, das die neue Seite darstellt. Dies muss keine Ansicht sein, kann aber auch ein anderer Container der Seite sein.
aber ich verstehe es immer noch nicht.
Hier ist mein Code. Ich verwende das Support Package v4.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
Hier ist auch jemand mit einem ähnlichen Problem, keine Antworten http://www.mail-archive.com/[email protected]/msg200477.html
Antworten:
Wenn Sie FragmentPagerAdapter oder FragmentStatePagerAdapter verwenden, ist es am besten, nur zu behandeln
getItem()
und überhaupt nicht zu berühreninstantiateItem()
. DieinstantiateItem()
-destroyItem()
-isViewFromObject()
Schnittstelle in PagerAdapter ist eine untergeordnete Schnittstelle, die FragmentPagerAdapter verwendet, um die viel einfacheregetItem()
Schnittstelle zu implementieren .Bevor ich darauf eingehe, sollte ich das klarstellen
Eine frühere Version dieser Antwort hat den Fehler gemacht, FragmentPagerAdapter als Beispiel zu verwenden - das funktioniert nicht, da FragmentPagerAdapter ein Fragment niemals zerstört, nachdem es zum ersten Mal angezeigt wurde.
Ich empfehle , die nicht
setTag()
undfindViewWithTag()
Abhilfe der Post , der Sie verknüpfen zur Verfügung gestellt. Wie Sie festgestellt haben, funktioniert es nicht mit FragmentensetTag()
undfindViewWithTag()
funktioniert nicht mit Fragmenten.Die richtige Lösung ist das Überschreiben
getItemPosition()
. WennnotifyDataSetChanged()
ViewPager aufgerufen wird, ruft esgetItemPosition()
alle Elemente in seinem Adapter auf, um festzustellen, ob sie an eine andere Position verschoben oder entfernt werden müssen.Standardmäßig wird
getItemPosition()
zurückgegebenPOSITION_UNCHANGED
, was bedeutet: "Dieses Objekt ist in Ordnung, wo es sich befindet. Zerstören oder entfernen Sie es nicht." Die RückgabePOSITION_NONE
behebt das Problem, indem stattdessen gesagt wird: "Dieses Objekt ist kein Element mehr, das ich anzeige. Entfernen Sie es." Dies bewirkt, dass jedes einzelne Element in Ihrem Adapter entfernt und neu erstellt wird.Dies ist eine völlig legitime Lösung! Durch diesen Fix verhält sich notifyDataSetChanged wie ein normaler Adapter ohne View-Recycling. Wenn Sie dieses Update implementieren und die Leistung zufriedenstellend ist, können Sie an den Rennen teilnehmen. Job erledigt.
Wenn Sie eine bessere Leistung benötigen, können Sie eine schickere
getItemPosition()
Implementierung verwenden. Hier ist ein Beispiel für einen Pager, der Fragmente aus einer Liste von Zeichenfolgen erstellt:Bei dieser Implementierung werden nur Fragmente angezeigt, die neue Titel anzeigen. Alle Fragmente, die Titel anzeigen, die sich noch in der Liste befinden, werden stattdessen an ihre neue Position in der Liste verschoben, und Fragmente mit Titeln, die überhaupt nicht mehr in der Liste enthalten sind, werden zerstört.
Was ist, wenn das Fragment nicht neu erstellt wurde, aber trotzdem aktualisiert werden muss? Aktualisierungen eines lebenden Fragments werden am besten vom Fragment selbst durchgeführt. Das ist schließlich der Vorteil eines Fragments - es ist ein eigener Controller. Ein Fragment kann einem anderen Objekt in einen Listener oder einen Beobachter hinzufügen
onCreate()
und es dann entfernenonDestroy()
, wodurch die Aktualisierungen selbst verwaltet werden. Sie müssen nicht den gesamten AktualisierungscodegetItem()
wie in einem Adapter für eine ListView oder andere AdapterView-Typen einfügen.Eine letzte Sache - nur weil FragmentPagerAdapter ein Fragment nicht zerstört, bedeutet dies nicht, dass getItemPosition in einem FragmentPagerAdapter völlig nutzlos ist. Mit diesem Rückruf können Sie Ihre Fragmente weiterhin im ViewPager neu anordnen. Sie werden jedoch niemals vollständig aus dem FragmentManager entfernt.
quelle
FragmentStatePagerAdapter
kann ich während der Verwendung feststellen, dass mein Fragment entfernt und die neue Instanz erstellt wird. Die neue Instanz erhält jedoch ein savedInstanceState-Bundle mit dem Status eines alten Fragments. Wie kann ich das Fragment vollständig zerstören, sodass Bundle beim erneuten Erstellen null ist?Statt der Rückkehr
POSITION_NONE
ausgetItemPosition()
und volle Sicht Erholung verursacht, dies zu tun:Ihre Fragmente sollten die
UpdateableFragment
Schnittstelle implementieren :und die Schnittstelle:
Ihre Datenklasse:
quelle
Fragment
dynamisch aktualisiere. Schauen Sie sich das an: stackoverflow.com/questions/19891828/…d page on refreshes the 1-st page only after swiping pages? thw 2
Seite immer leer angezeigt . dankefür diejenigen, die immer noch das gleiche Problem haben, mit dem ich vorher konfrontiert war, als ich ein
ViewPager
mit 7 Fragmenten habe. Die Standardeinstellung für diese Fragmente zum Laden des englischen Inhalts aus demAPI
Dienst, aber das Problem hier, dass ich die Sprache aus der Einstellungsaktivität ändern möchte und nach Abschluss der EinstellungsaktivitätViewPager
in der Hauptaktivität die Fragmente aktualisieren soll, um sie an die Sprachauswahl des Benutzers anzupassen und zu laden Der arabische Inhalt, wenn der Benutzer hier Arabisch wählt, was ich getan habe, um vom ersten Mal an zu arbeiten1- Sie müssen FragmentStatePagerAdapter wie oben erwähnt verwenden.
2- on mainActivity Ich habe den onResume überschrieben und Folgendes getan
3-i hat den
getItemPosition()
in mPagerAdapter überschrieben und zurückgeben lassenPOSITION_NONE
.wirkt wie Charme
quelle
Ich bin auf dieses Problem gestoßen und habe es heute endlich gelöst. Ich schreibe auf, was ich gelernt habe, und hoffe, dass es für jemanden hilfreich ist, der neu bei Android ist
ViewPager
und wie ich aktualisiere. Ich verwendeFragmentStatePagerAdapter
in API Level 17 und habe derzeit nur 2 Fragmente. Ich denke, es muss etwas nicht korrekt sein, bitte korrigieren Sie mich, danke.Serialisierte Daten müssen in den Speicher geladen werden. Dies kann unter Verwendung eines
CursorLoader
/AsyncTask
/Thread
. Ob es automatisch geladen wird, hängt von Ihrem Code ab. Wenn Sie a verwendenCursorLoader
, wird es automatisch geladen, da ein registrierter Datenbeobachter vorhanden ist.Nach dem Aufruf
viewpager.setAdapter(pageradapter)
wird der AdaptergetCount()
ständig aufgerufen, um Fragmente zu erstellen. Wenn also Daten geladen werden,getCount()
kann 0 zurückgegeben werden, sodass Sie keine Dummy-Fragmente für keine angezeigten Daten erstellen müssen.Nachdem die Daten geladen wurden, erstellt der Adapter keine Fragmente automatisch, da sie
getCount()
immer noch 0 sind. Daher können wir die tatsächlich geladene Datennummer festlegen, von der zurückgegeben werden sollgetCount()
, und dann die Adapter aufrufennotifyDataSetChanged()
.ViewPager
Beginnen Sie mit der Erstellung von Fragmenten (nur die ersten beiden Fragmente) anhand von Daten im Speicher. Es ist fertig, bevornotifyDataSetChanged()
es zurückgegeben wird. DannViewPager
hat der die richtigen Fragmente, die Sie brauchen.Wenn die Daten in der Datenbank und im Speicher beide aktualisiert werden (Durchschreiben) oder nur Daten im Speicher aktualisiert werden (Zurückschreiben) oder nur Daten in der Datenbank aktualisiert werden. In den letzten beiden Fällen, wenn Daten nicht automatisch aus der Datenbank in den Speicher geladen werden (wie oben erwähnt). Der
ViewPager
und der Pager-Adapter verarbeiten nur Daten im Speicher.Wenn also die Daten im Speicher aktualisiert werden, müssen wir nur die Adapter aufrufen
notifyDataSetChanged()
. Da das Fragment bereits erstellt wurde, werden die AdapteronItemPosition()
vor dernotifyDataSetChanged()
Rückkehr aufgerufen . Es muss nichts getan werdengetItemPosition()
. Dann werden die Daten aktualisiert.quelle
notifyDataSetChanged()
einfach an und aktualisieren Sie sie einfach automatisch, da sich das von mir verwendete Fragment (mit Diagrammansicht) selbst aktualisiert. Wenn es nicht wie ein statisches Fragment ist, muss ich anrufenonItemPositon()
und esPOSITION_NONE
tut mir leidProbieren Sie
destroyDrawingCache()
ViewPager nachnotifyDataSetChanged()
in Ihrem Code aus.quelle
Fragments
in meinem View Pager verwende. Also vielen Dank!Nach stundenlanger Frustration beim Ausprobieren aller oben genannten Lösungen, um dieses Problem zu überwinden, und auch beim Ausprobieren vieler Lösungen für andere ähnliche Fragen wie diese , dies und das, die alle mit mir gescheitert sind, um dieses Problem zu lösen und
ViewPager
das Alte zu zerstörenFragment
und daspager
mit zu füllen die neuenFragment
s. Ich habe das Problem wie folgt gelöst:1) Stellen Sie sicher, dass die
ViewPager
KlasseFragmentPagerAdapter
wie folgt erweitert wird:2) Erstellen Sie ein Element für das
ViewPager
, in dem dastitle
und dasfragment
folgende gespeichert sind :3) Lassen Sie den Konstruktor von
ViewPager
take myFragmentManager
instanceclass
wie folgt in my speichern :4) Erstellen Sie eine Methode zur Wieder stellen Sie die
adapter
Daten mit den neuen Daten durch alle vorherigen Löschenfragment
aus derfragmentManager
sich direkt um dieadapter
die neue zu setzenfragment
aus der neuen Liste wieder , wie folgend:5) Aus dem Container
Activity
oderFragment
initialisieren Sie den Adapter nicht mit den neuen Daten neu. Stellen Sie die neuen Daten durch die MethodesetPagerItems
mit den neuen Daten wie folgt ein:Ich hoffe, es hilft.
quelle
Aus irgendeinem Grund funktionierte keine der Antworten für mich, so dass ich die restoreState-Methode überschreiben musste, ohne super in meinem fragmentStatePagerAdapter aufzurufen. Code:
quelle
Ich habe die von Bill Phillips bereitgestellte Lösung leicht an meine Bedürfnisse angepasst
Damit wird die
getItemPosition()
RückgabePOSITION_NONE
nur für die Fragmente aufgerufen, die sich aktuell imFragmentManager
WanngetItemPosition
befinden. (Beachten Sie, dass diesFragmentStatePager
und die damitViewPager
verbundenen Elemente in einem Fragment enthalten sind, das nicht in einer Aktivität enthalten ist.)quelle
Ich hatte ein ähnliches Problem, möchte aber nicht auf die vorhandenen Lösungen (fest codierte Tag-Namen usw.) vertrauen und konnte die Lösung von M-WaJeEh nicht für mich arbeiten lassen. Hier ist meine Lösung:
Ich behalte Verweise auf die in getItem erstellten Fragmente in einem Array. Dies funktioniert einwandfrei, solange die Aktivität nicht aufgrund von Konfigurationsänderungen oder Speichermangel oder was auch immer zerstört wird (-> Wenn Fragmente zur Aktivität zurückkehren, kehren sie in ihren letzten Zustand zurück, ohne dass 'getItem' erneut aufgerufen wird und somit das Array nicht aktualisiert wird ).
Um dieses Problem zu vermeiden, habe ich instantiateItem (ViewGroup, int) implementiert und mein Array dort wie folgt aktualisiert:
Einerseits bin ich froh, dass ich eine Lösung gefunden habe, die für mich funktioniert, und wollte sie mit Ihnen teilen, aber ich wollte auch fragen, ob jemand anderes etwas Ähnliches versucht hat und ob es einen Grund gibt, warum ich es nicht tun sollte mach es so Bisher funktioniert es sehr gut für mich ...
quelle
myFragments
in entfernen sollten,public void destroyItem(ViewGroup container, int position, Object object)
damit Sie keine veraltete Fraging-Referenz abrufen.Ich verwende die EventBus- Bibliothek, um
Fragment
Inhalte in zu aktualisierenViewPager
. Die Logik ist einfach, genau wie das Dokument von EventBus . DieFragmentPagerAdapter
Instanz muss nicht gesteuert werden. Der Code ist hier:1: Ereignisse definieren
Definieren Sie, welche Nachricht aktualisiert werden soll.
2. Bereiten Sie die Abonnenten vor
Schreiben Sie den folgenden Code in das Fragment, das aktualisiert werden muss.
3.Post-Ereignisse
Schreiben Sie den folgenden Code in einen anderen
Activity
oder anderen CodeFragment
, der aktualisiert werden mussquelle
Wenn Sie FragmentStatePagerAdapter verwenden möchten, besuchen Sie bitte https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% 20Stars & groupby = & sort = & id = 37990 . Es gibt Probleme mit FragmentStatePagerAdapter, die Ihren Anwendungsfall möglicherweise stören oder nicht.
Außerdem hat Link auch nur wenige Lösungen. Nur wenige können Ihren Anforderungen entsprechen.
quelle
Ich habe das gleiche Problem gelebt und zu oft gesucht. Eine Antwort im Stackoverflow oder über Google war keine Lösung für mein Problem. Mein Problem war einfach. Ich habe eine Liste, ich zeige diese Liste mit Viewpager. Wenn ich ein neues Element zum Kopf der Liste hinzufüge und den Viewpager aktualisiere, ändert sich nichts. Meine endgültige Lösung war sehr einfach, die jeder verwenden kann. Wenn ein neues Element zur Liste hinzugefügt wird und die Liste aktualisiert werden soll. Setzen Sie zuerst den Viewpager-Adapter auf null, erstellen Sie dann den Adapter neu und setzen Sie i auf den Viewpager.
Stellen Sie sicher, dass Ihr Adapter FragmentStatePagerAdapter erweitern muss
quelle
Hier ist meine Implementierung, die die Informationen von @Bill Phillips One enthält. Die meiste Zeit wird ein Fragment zwischengespeichert, außer wenn sich die Daten geändert haben. Einfach und scheint gut zu funktionieren.
MyFragmentStatePagerAdapter.java
MyActivity.java
quelle
Ich hatte so viele verschiedene Ansätze ausprobiert, dass keiner mein Problem wirklich gelöst hat. Im Folgenden wird beschrieben, wie ich es mit einer Mischung von Lösungen löse, die von Ihnen allen bereitgestellt werden. Vielen Dank an alle.
Ich möchte Seite 0 erst nach onResume () aktualisieren.
In meinem FragmentsMain gibt es eine öffentliche Ganzzahl "Seite", die mir sagen kann, ob es sich um die Seite handelt, die ich aktualisieren möchte.
quelle
Ich weiß, dass ich zu spät zur Party komme. Ich habe das Problem behoben, indem ich
TabLayout#setupWithViewPager(myViewPager);
gleich danach anriefFragmentPagerAdapter#notifyDataSetChanged();
quelle
Diese Lösung funktioniert nicht für alle, aber in meinem Fall ist jedes Fragment in meinem ViewPager eine andere Klasse, und es existiert immer nur eine.
Mit dieser Einschränkung ist diese Lösung sicher und sollte in der Produktion sicher verwendet werden können.
Wenn Sie mehrere Versionen desselben Fragments haben, können Sie mit derselben Strategie Methoden für diese Fragmente aufrufen, um festzustellen, ob es sich um das Fragment handelt, das Sie aktualisieren möchten.
quelle
Dies kann für jemanden hilfreich sein. In meinem Fall hat der Ansichtspager beim Einfügen einer neuen Seite zweimal nach der Position eines vorhandenen Fragments gefragt, aber nicht nach der Position des neuen Elements, was zu falschem Verhalten und nicht angezeigten Daten führte.
Kopieren Sie die Quelle für FragmentStatePagerAdapter (scheint seit Jahren nicht mehr aktualisiert worden zu sein).
Überschreiben Sie notifyDataSetChanged ()
Fügen Sie destroyItem () eine Überprüfung der Integrität hinzu, um Abstürze zu vermeiden:
quelle
Ich habe alle obigen Antworten und eine Reihe anderer Beiträge durchgesehen, konnte aber immer noch nichts finden, was für mich funktioniert (mit verschiedenen Fragmenttypen sowie dem dynamischen Hinzufügen und Entfernen von Registerkarten). Der folgende FWIW-Ansatz hat bei mir funktioniert (falls jemand anderes die gleichen Probleme hat).
quelle
Verwenden Sie FragmentStatePagerAdapter anstelle von FragmentPagerAdapter, wenn Sie Fragmente auf Indexbasis neu erstellen oder neu laden möchten. Wenn Sie beispielsweise ein anderes Fragment als FirstFragment neu laden möchten, können Sie die Instanz überprüfen und die Position wie folgt zurückgeben
quelle
Sie müssen das mFragments-Element getItemPosition von instantiateItem ändern.
Basierend auf AndroidX FragmentStatePagerAdapter.java, da sich
mFragments
die Position der Elemente beim Aufruf von notifyDataSetChanged () nicht ändert.Quelle: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java
Beispiel: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt
Sie können dieses Projekt ausführen, um die Arbeitsweise zu bestätigen. https://github.com/cuichanghao/infivt
quelle