8

Ich versuche, das gleiche Design als PlayStore 5.1.x zu haben. Hier ist mein Layout:ViewPager erstes Fragment ist immer falsch mit FragmentStatePager

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_gravity="center_vertical|center_horizontal" 
    android:gravity="center_vertical|center_horizontal" 
    android:orientation="vertical"> 

    <com.astuetz.PagerSlidingTabStrip 
     android:id="@+id/tabs" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" 
     android:background="@drawable/background_tabs" /> 

    <android.support.v4.view.ViewPager 
     android:id="@+id/pager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

</LinearLayout> 

Mein Adapter:

public class MainPagerAdapter extends FragmentStatePagerAdapter { 

    private ArrayList<FakeFragment> fragments; 

    public MainPagerAdapter(FragmentManager fm) { 
     super(fm); 
     // TODO Auto-generated constructor stub 
     fragments = new ArrayList<FakeFragment>(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     // TODO Auto-generated method stub  
     if(position < getCount()) { 
      FakeFragment fragment = FakeFragment.newInstance(position); 
      fragments.add(fragment); 
     } 
     return fragments.get(position); 
    } 

    @Override 
    public int getCount() { 
     // TODO Auto-generated method stub 
     return Category.values().length; 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     // TODO Auto-generated method stub 
     return Category.values()[position].getTitle(); 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     // TODO Auto-generated method stub 
     return POSITION_NONE; 
    } 
} 

Meine Tabs und Pager zeigen richtig! aber ich habe bemerkt, dass das erste Fragment, das im View-Pager angezeigt wird, immer dasselbe ist wie das zweite. Dann, wenn ich einmal, zweimal wische und zurück zur ersten Seite wische, finde ich, dass das korrekte Fragment jetzt gezeigt wird !!

Ich kann nicht verstehen, warum dieses Verhalten, bitte ich brauche einige Erklärungen.

SOLUTION

Das Problem war, meine FakeFragment.newInstance() Methodendefinition zurückzuführen.

private static int position; 

public static FakeFragment newInstance(int position) { 
    // TODO Auto-generated method stub 
    FakeFragment.position = position; 
    return new FakeFragment(); 
} 

habe ich es durch ein setArguments(args) meine FakeFragment Instanz verwendet wird, und es dann in onCreate Methode abrufen. Jetzt funktioniert alles gut!

Kann mir jemand erklären warum?

Ich denke, dass auf diese Weise Wert der Position wird vollständig abhängig von Fragment Lebenszyklus, so wird immer die erwartete Position sein, nicht wahr?

+1

Entfernen Sie 'private ArrayList -Fragmente' und geben Sie mit' getItem() 'eine neue Instanz des Fragments zurück. Der ** komplette und vollständige * Punkt *** hinter 'FragmentStatePagerAdapter' soll ** NICHT ** alle Fragmente im Speicher halten. Wenn das das ist, was Sie wollen, dann werden Sie immer noch die 'ArrayList ' los und wechseln Sie Ihren Adapter zu einem 'FragmentPagerAdapter' anstatt einem' FragmentStatePagerAdapter'. Befreie auch 'getItemPosition()'. [FWIW, hier sind eine Reihe von Beispielen 'ViewPager'-Apps] (https://github.com/commonsguy/cw-omnibus/tree/master/ViewPager). – CommonsWare

+0

Danke @CommonsWare. Ich habe den 'FragmentStatePagerAdapter' gewählt, weil ich 6 Seiten in meinem' ViewPager' habe, auf jeder Seite habe ich eine 'GridView' mit vielen Daten zum Anzeigen.Deshalb wollte ich diese Art von Adapter verwenden, um eine Seite neu zu erstellen oder den Inhalt nur bei Bedarf zu aktualisieren. Deshalb habe ich auch versucht, 'getItemPosition' zu überschreiben. Ist das mit 'FragmentPagerAdapter' möglich? danke nochmal für die antwort! –

+1

Ihre Implementierung sollte in beiden Fällen korrekt funktionieren, nur die Geschwindigkeit kann unterschiedlich sein. Wenn das Laden von Daten teuer ist und Sie nicht jedes Mal 'FragmentStatePagerAdapter' verwenden müssen, verwenden Sie 'Fragment.onSaveInstanceState', um den geladenen Datensatz zu speichern. –

Antwort

6

1) Implementieren Sie nicht getItemPosition(Object), wenn Sie nicht damit umgehen. Sie sind nicht verpflichtet, es zu implementieren, und Sie könnten andere Funktionen durch falsche Implementierung brechen.

2) Der Punkt ist, ein neues Fragment zurückzugeben. Ziehen Sie das Fragment-Array ab, da es keinen Sinn ergibt.

3) Machen Sie die Adpater-Klasse static (Es fördert die Wiederverwendbarkeit, der Adapter sollte nicht von der Elternklasse abhängen, um seine Daten zu bekommen, oder?) Und übergeben Sie die Category s als Konstruktor Parameter. Speichern Sie es in einer Variablen und erstellen Sie neue Fragmente gemäß diesem Datensatz. Wahrscheinlich möchten Sie auch einen Category[position] als Parameter an den Fragmentkonstruktor übergeben und nicht nur position.

+0

Dank @Eugen, bitte geben Sie weitere Informationen über die 3): 'Der Adapter sollte nicht auf die Elternklasse zu erhalten sein Datensatz? –

+1

Es empfiehlt sich, verschachtelte Klassen 'static' zu deklarieren. Dadurch wird die implizite Verbindung zur übergeordneten Klasse entfernt (beachten Sie, dass Sie nicht auf die Feldvariablen des übergeordneten Elements zugreifen können). In einigen Fällen kann dies Speicherlecks verhindern. Verwenden Sie nur nicht statische innere Klassen, wenn Sie wissen, was Sie tun. Versuchen Sie [das] (http://stackoverflow.com/a/70358/2444099) zu lesen. –

+0

Ich habe Ihre Antwort angenommen und Ihnen die Prämien gegeben, weil Ihre Antwort und mein Kommentar mich zu anderen nützlichen Informationen geführt haben. –

3

Die getItem() Implementierung ist das Problem.

@Override 
public Fragment getItem(final int position) { 
    return FakeFragment.newInstance(position); 
} 

Sie sollten niemals die Daten in dieser get-Methode ändern: rufen Sie nicht add() drin. Ich bezweifle, dass die Adapter an dieser Stelle wissen würde, dass Sie ein Element hinzugefügt haben.

Verwandte Themen