
C0deAttack
Ich verwende den ViewPager aus der Kompatibilitätsbibliothek. Ich habe erfolgreich mehrere Ansichten angezeigt, die ich durchblättern kann.
Es fällt mir jedoch schwer, herauszufinden, wie ich den ViewPager mit einem neuen Satz von Ansichten aktualisieren kann.
Ich habe schon alles Mögliche ausprobiert, zum Beispiel anrufen mAdapter.notifyDataSetChanged()
, mViewPager.invalidate()
Ich erstelle sogar jedes Mal einen brandneuen Adapter, wenn ich eine neue Datenliste verwenden möchte.
Nichts hat geholfen, die Textansichten bleiben gegenüber den Originaldaten unverändert.
Aktualisieren:
Ich habe ein kleines Testprojekt gemacht und konnte die Ansichten fast aktualisieren. Ich füge die Klasse unten ein.
Was jedoch nicht aktualisiert zu werden scheint, ist die zweite Ansicht, das „B“ bleibt, es sollte „Y“ anzeigen, nachdem die Schaltfläche „Aktualisieren“ gedrückt wurde.
public class ViewPagerBugActivity extends Activity {
private ViewPager myViewPager;
private List<String> data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
data = new ArrayList<String>();
data.add("A");
data.add("B");
data.add("C");
myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
myViewPager.setAdapter(new MyViewPagerAdapter(this, data));
Button updateButton = (Button) findViewById(R.id.update_button);
updateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
updateViewPager();
}
});
}
private void updateViewPager() {
data.clear();
data.add("X");
data.add("Y");
data.add("Z");
myViewPager.getAdapter().notifyDataSetChanged();
}
private class MyViewPagerAdapter extends PagerAdapter {
private List<String> data;
private Context ctx;
public MyViewPagerAdapter(Context ctx, List<String> data) {
this.ctx = ctx;
this.data = data;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object instantiateItem(View collection, int position) {
TextView view = new TextView(ctx);
view.setText(data.get(position));
((ViewPager)collection).addView(view);
return view;
}
@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
@Override
public void startUpdate(View arg0) {
}
@Override
public void finishUpdate(View arg0) {
}
}
}

Alvaro Luis Bustamante
Ich glaube nicht, dass da irgendein Bug drin ist PagerAdapter
. Das Problem ist, dass es etwas komplex ist, zu verstehen, wie es funktioniert. Wenn man sich die hier erläuterten Lösungen ansieht, gibt es aus meiner Sicht ein Missverständnis und daher eine schlechte Verwendung von instanziierten Ansichten.
Die letzten Tage habe ich mit gearbeitet PagerAdapter
und ViewPager
und ich habe folgendes gefunden:
Das notifyDataSetChanged()
Methode auf der PagerAdapter
wird nur die benachrichtigen ViewPager
dass sich die zugrunde liegenden Seiten geändert haben. Wenn Sie beispielsweise Seiten dynamisch erstellt/gelöscht haben (Elemente zu Ihrer Liste hinzufügen oder daraus entfernen), wird die ViewPager
sollte sich darum kümmern. In diesem Fall denke ich, dass die ViewPager
bestimmt, ob eine neue Ansicht gelöscht oder mithilfe von instanziiert werden soll getItemPosition()
und getCount()
Methoden.
ich denke, dass ViewPager
nach einer notifyDataSetChanged()
call nimmt seine untergeordneten Ansichten auf und überprüft deren Position mit der getItemPosition()
. Wenn diese Methode für eine untergeordnete Ansicht zurückkehrt POSITION_NONE
das ViewPager
versteht, dass die Ansicht gelöscht wurde, ruft die auf destroyItem()
und entfernen Sie diese Ansicht.
Auf diese Weise überschreiben getItemPosition()
immer wiederzukommen POSITION_NONE
ist völlig falsch, wenn man nur den Inhalt der Seiten aktualisieren möchte, da bei jedem Aufruf die zuvor erstellten Ansichten zerstört und neue erstellt werden notifyDatasetChanged()
. Es mag scheinen, nur für wenige nicht so falsch zu sein TextView
s, aber wenn Sie komplexe Ansichten haben, wie ListViews, die aus einer Datenbank gefüllt werden, kann dies ein echtes Problem und eine Verschwendung von Ressourcen sein.
Es gibt also mehrere Ansätze, um den Inhalt einer Ansicht effizient zu ändern, ohne die Ansicht entfernen und erneut instanziieren zu müssen. Es hängt von dem Problem ab, das Sie lösen möchten. Mein Ansatz ist die Verwendung von setTag()
-Methode für jede instanziierte Ansicht in der instantiateItem()
Methode. Wenn Sie also die Daten ändern oder die benötigte Ansicht ungültig machen möchten, können Sie die aufrufen findViewWithTag()
Methode auf der ViewPager
um die zuvor instanziierte Ansicht abzurufen und sie nach Belieben zu ändern/zu verwenden, ohne jedes Mal, wenn Sie einen Wert aktualisieren möchten, eine neue Ansicht löschen/erstellen zu müssen.
Stellen Sie sich zum Beispiel vor, Sie haben 100 Seiten mit 100 TextView
s und Sie nur einen Wert regelmäßig aktualisieren möchten. Mit den zuvor erläuterten Ansätzen bedeutet dies, dass Sie 100 entfernen und instanziieren TextView
s bei jedem Update. Es ergibt keinen Sinn…

Grimasse
Die Antwort von alvarolb ist definitiv der beste Weg, dies zu tun. Aufbauend auf seiner Antwort besteht eine einfache Möglichkeit, dies zu implementieren, darin, die aktiven Ansichten einfach nach Position zu speichern:
SparseArray<View> views = new SparseArray<View>();
@Override
public Object instantiateItem(View container, int position) {
View root = <build your view here>;
((ViewPager) container).addView(root);
views.put(position, root);
return root;
}
@Override
public void destroyItem(View collection, int position, Object o) {
View view = (View)o;
((ViewPager) collection).removeView(view);
views.remove(position);
view = null;
}
Dann einmal durch Überschreiben der notifyDataSetChanged
Methode können Sie die Ansichten aktualisieren …
@Override
public void notifyDataSetChanged() {
int key = 0;
for(int i = 0; i < views.size(); i++) {
key = views.keyAt(i);
View view = views.get(key);
<refresh view with new data>
}
super.notifyDataSetChanged();
}
Sie können tatsächlich ähnlichen Code in verwenden instantiateItem
und notifyDataSetChanged
um Ihre Ansicht aufzufrischen. In meinem Code verwende ich genau die gleiche Methode.

Tonys
Hatte das gleiche Problem. Für mich hat es funktioniert, FragmentStatePagerAdapter zu erweitern und die folgenden Methoden zu überschreiben:
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}

Gemeinschaft
Nach Stunden der Frustration beim Ausprobieren aller oben genannten Lösungen zur Überwindung dieses Problems und auch beim Ausprobieren vieler Lösungen zu anderen ähnlichen Fragen wie dieser, dieser und dieser, die alle bei mir fehlschlugen, dieses Problem zu lösen und das zu machen ViewPager
das Alte zu zerstören Fragment
und fülle die pager
mit dem neuen Fragment
s. Ich habe das Problem wie folgt gelöst:
1) Mach das ViewPager
Klasse zu erweitern FragmentPagerAdapter
wie folgt:
public class myPagerAdapter extends FragmentPagerAdapter {
2) Erstellen Sie ein Element für die ViewPager
die speichern title
und der fragment
wie folgt:
public class PagerItem {
private String mTitle;
private Fragment mFragment;
public PagerItem(String mTitle, Fragment mFragment) {
this.mTitle = mTitle;
this.mFragment = mFragment;
}
public String getTitle() {
return mTitle;
}
public Fragment getFragment() {
return mFragment;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public void setFragment(Fragment mFragment) {
this.mFragment = mFragment;
}
}
3) Machen Sie den Konstruktor der ViewPager
Nimm mein FragmentManager
Beispiel, um es in my zu speichern class
wie folgt:
private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;
public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
super(fragmentManager);
mFragmentManager = fragmentManager;
mPagerItems = pagerItems;
}
4) Erstellen Sie eine Methode zum Zurücksetzen der adapter
Daten mit den neuen Daten durch Löschen aller vorherigen fragment
von dem fragmentManager
selbst direkt zu machen adapter
das neue einzustellen fragment
aus der neuen Liste wieder wie folgt:
public void setPagerItems(ArrayList<PagerItem> pagerItems) {
if (mPagerItems != null)
for (int i = 0; i < mPagerItems.size(); i++) {
mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
}
mPagerItems = pagerItems;
}
5) Aus dem Behälter Activity
oder Fragment
initialisieren Sie den Adapter nicht mit den neuen Daten neu. Stellen Sie die neuen Daten durch die Methode ein setPagerItems
mit den neuen Daten wie folgt:
ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));
mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();
Ich hoffe, es hilft.
10151300cookie-checkWarum aktualisiert `PagerAdapter::notifyDataSetChanged` die Ansicht nicht?yes
Unter stackoverflow.com/questions/12510404/… finden Sie einen potenziellen Fehler mit dem FragmentStatePagerAdapter.
– samus
21. Januar 2014 um 20:12 Uhr
Tut mir leid, das auszugraben. Deine Frage hat mir wirklich geholfen, danke! Das einzige, was ich nicht verstehe, ist, wie der Verweis auf Daten im PagerAdapter geändert wird, wenn Sie ihn in der Aktivität aktualisieren
– Ewanw
13. Juli 2015 um 22:54 Uhr
Lassen Sie Ihren Adapter BaseAdapter erweitern. Siehe: stackoverflow.com/questions/13664155/…
– Benutzer5219444
12. August 2015 um 13:04 Uhr
Anscheinend, wenn Sie den Adapter wieder auf Ihren View-Pager einstellen, dann wird er zurückgesetzt.
– EpicPandaForce
11. Februar 2016 um 21:27 Uhr
Ich habe ein Problem mit dem Pager stackoverflow.com/questions/41217237/…
– Chris
21. Dezember 2016 um 12:27 Uhr