2012-05-18 7 views
16

Sto lavorando con un FragmentStatePagerAdapter utilizzando this example.Android FragmentStatePagerAdapter

La classe MyAdapter è implementata come segue:

public static class MyAdapter extends FragmentStatePagerAdapter { 
     public MyAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public int getCount() { 
      return NUM_ITEMS; 
     } 

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

classe La ListFragment comprende il seguente metodo per creare una nuova istanza:

/** 
    * Create a new instance of CountingFragment, providing "num" 
    * as an argument. 
    */ 
    static ArrayListFragment newInstance(int num) { 
     ArrayListFragment f = new ArrayListFragment(); 

     // Supply num input as an argument. 
     Bundle args = new Bundle(); 
     args.putInt("num", num); 
     f.setArguments(args); 

     return f; 
    } 

Quando creo un nuovo adattatore pager stato frammento nel mio viene chiamato il numero getItem, che a sua volta chiama il metodo newInstance nella classe ListFragment. Questo è fantastico quando voglio creare un nuovo frammento.

Ma non è chiaro per me come modificare getItem (se ancora necessario) per ottenere l'oggetto frammento quando esiste già e le pagine degli utenti da, per esempio, pagina 2 a pagina 1. Vorrei che il mio Attività per recuperare quel frammento esistente creato in precedenza in modo che possa eseguire una classe interna AsyncMethod, che risiede nella classe frammento.

+2

'getItem()' ha un nome strano, non fornisce la funzionalità che stai pensando di. Per favore controlla la mia stessa domanda sullo stesso argomento: http://stackoverflow.com/questions/10574114/referencing-fragments-inside-viewpager –

+0

Questo sembra molto utile. Ma sto usando un ListFragment e speravo di usare getSelectedItemPosition invece di creare la mia getPosition. Ho bisogno di giocarci ancora un po 'e vedere se riesco a capire come farlo. – mraviator

+0

Ho usato anche ListFragment, ma semplicemente non funziona in questo modo. Tuttavia, se trovi qualcosa, sarei felice di sapere –

risposta

3

Ho implementato qualcosa di simile a quello che hai. Ho esteso la classe FragmentPagerAdapter in questo modo:

public class ContactsFragmentPagerAdapter extends FragmentPagerAdapter { 
    ActionBar mActionBar; 
    private List<Fragment> mFragments; 

    public ContactsFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) { 
     super(fm); 
     mFragments = fragments; 
    } 

    @Override 
    public int getCount() { 
     return mFragments.size(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return mFragments.get(position); 
    } 

    public void setActionBar(ActionBar bar) { 
     mActionBar = bar; 
    } 
} 

Avviso Ho aggiunto un argomento al costruttore di passare nelle List di Fragment oggetti. In questo modo il metodo getItem() di questa classe può restituire qualsiasi classe che estende Fragment o una qualsiasi delle sue sottoclassi e non solo una classe specifica ArrayListFragment come è stato fatto.

Nel Activity dove ho un'istanza di mia sottoclasse di FragmentPagerAdapter ho passato nella lista degli Fragment oggetti:

classe del un'istanza della FragmentPagerAdapter

public final class ContactManager extends Activity { 
    private ContactsFragmentPagerAdapter mAdapter; 
    private ViewPager mPager; 
    public ActionBar mActionBar; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.contact_manager); 

     List<Fragment> fragments = new Vector<Fragment>(); 
     fragments.add(Fragment.instantiate(this, ContactsListFragment.class.getName())); 
     fragments.add(Fragment.instantiate(this, GroupsListFragment.class.getName())); 
     mAdapter = new ContactsFragmentPagerAdapter(this.getFragmentManager(), fragments); 

     mPager = (ViewPager) findViewById(R.id.pager); 
     mPager.setAdapter(mAdapter); 

     mPager.setOnPageChangeListener(new OnPageChangeListener() { 
      @Override 
      public void onPageScrollStateChanged(int arg0) {} 

      @Override 
      public void onPageScrolled(int arg0, float arg1, int arg2) {} 

      @Override 
      public void onPageSelected(int arg0) { 
       mActionBar.getTabAt(arg0).select(); 
      } 
     }); 

    } 

} 

Accedendo ai "frammenti" variabile, è possibile accedere a uno Fragment creato in precedenza in modo da poter eseguire i metodi di tale Fragment.

+13

Sarebbe bello se ci fosse una soluzione che non tenesse tutti i frammenti sempre istanziati per funzionare bene con 'FragmentStatePagerAdapter', dal momento che questo è davvero il punto centrale di quell'adattatore. – blahdiblah

+2

@blahdiblah Dai un'occhiata alla mia risposta. – imiric

4
public class MyPagerAdapter extends FragmentStatePagerAdapter { 
    final Context m_context; 
    final WeakReference<Fragment>[] m_fragments; 

    public DetailPagerAdapter(FragmentManager fm) { 
     super(fm); 
     m_context = ... 
       m_fragments = new WeakReference[enter size here]; 
    } 

    @Override 
    public Fragment getItem(int position) { 
     final Fragment fragment = instantiate your fragment; 
     m_fragments[position] = new WeakReference<Fragment>(fragment); 
     return fragment; 
    } 

    @Override 
    public int getCount() { 
     return ... 
    } 

    public Fragment getFragment(final int position) { 
     return m_fragments[position] == null ? null : 
      m_fragments[position].get(); 
    } 
} 
+0

Per me questo è il modo più economico, grazie – j2emanue

0

Non è necessario modificare FragmentPagerAdapter, poiché i frammenti sono memorizzati nella cache da FragmentManager. Quindi devi aver bisogno di trovarlo al suo interno. Utilizzare questa funzione per trovare il frammento in base alla posizione dell'adattatore cercapersone.

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

Codice di esempio per il supporto v4 api.

+0

Questo è incluso nel codice di esempio per l'API di supporto o lo hai scritto tu stesso per l'API di supporto? (Se è lì, sarei almeno 'semi-ufficiale') – Patrick

+0

Scrivo questo da solo, in base al codice sorgente dell'API Android, e il significato di "codice di esempio per v4" è perché questo codice utilizza "getSupportFragmentManager "che è disponibile quando si utilizza la libreria di supporto, nel caso in cui non si usi la 'libreria di supporto', sarà necessario almeno modificare" getSupportFragmentManager "per" getFragmentManager ". FYI: http://developer.android.com/tools/extras/support-library.html –

+1

Thx. Speravo che in qualche modo l'avessero reso ufficiale. Questo potrebbe rompersi in futuro ... Ah bene, ma grazie! – Patrick

37

Penso che la soluzione sia molto più semplice delle risposte fornite.

Se si dà un'occhiata alla source of FragmentStatePagerAdapter.instantiateItem(), si noterà che instantiateItem() gestisce questa logica per voi, e quindi l'implementazione di getItem() dovrebbe sempre restituire una nuova istanza.

Quindi, al fine di restituire un frammento esistente, semplicemente (supponendo che si sta chiamando da ViewPager):

Fragment f = (Fragment) getAdapter().instantiateItem(this, getCurrentItem()); 
+4

La migliore risposta era nascosta in fondo !!! public void onPageScrolled (int i, float v, int i2) { Frammento frammento = (Frammento) imagePagerAdapter.instantiateItem (mImageViewPager, i); –

+2

Solo dopo aver guardato la fonte ho realizzato la logica del problema. E vedi che questa è l'unica risposta logica sulla pagina. Grazie mille. –

+1

Ottima risposta, grazie. –

5

Mentre @ di imiric soluzione è molto conciso, mi dà fastidio ancora che richiede la conoscenza del implementazione della classe. La mia soluzione comporta l'aggiunta la seguente alla scheda, che dovrebbe comportarsi bene con un FragmentStatePagerAdapter possibilmente distruggere frammenti:

private SparseArray<WeakReference<Fragment>> mFragments = new SparseArray<>(); 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     Fragment f = (Fragment) super.instantiateItem(container, position); 
     mFragments.put(position, new WeakReference<>(f)); // Remember what fragment was in position 
     return f; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     super.destroyItem(container, position, object); 
     mFragments.remove(position); 
    } 

    public Fragment getFragment(int position) { 
     WeakReference<Fragment> ref = mFragments.get(position); 
     Fragment f = ref != null ? ref.get() : null; 
     if (f == null) { 
      Log.d(TAG, "fragment for " + position + " is null!"); 
     } 
     return f; 
    } 
+3

Non si dovrebbero mantenere riferimenti a Frammenti poiché possono essere distrutti e ricreati in qualsiasi momento. I tuoi riferimenti non saranno validi se ciò accade e i Frammenti non possono essere raccolti. – wkarl

+0

Davvero! Tuttavia, l'aggiornamento di WeakReferences non sarebbe sufficiente? – qix

+0

Lo penserei – wkarl

Problemi correlati