2012-05-13 15 views
9

Ho un problema con riferimento miei frammenti all'interno di un ViewPager. Mi piacerebbe farlo perché dalla mia attività mi piacerebbe aggiornare un frammento in una posizione specificata (ad esempio frammento attualmente visualizzato).Frammenti Riferimenti a all'interno ViewPager

Attualmente ho qualcosa di simile:

public static class MyPagerAdapter extends FragmentPagerAdapter { 

    private static final String TAG = "MyPagerAdapter"; 
    private static HashMap<Integer, EventListFragment> mPageReferenceMap = new HashMap<Integer, EventListFragment>(); 

    public MyPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

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

    @Override 
    public Fragment getItem(int position) { 
     Log.i(TAG, "getItem: "+position); 
     int dateOffset = position-1; 
     EventListFragment mFragment = EventListFragment.newInstance(dateOffset); 
     mPageReferenceMap.put(position, mFragment); 
     return mFragment; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     Log.i(TAG, "destroyItem: "+position); 
     mPageReferenceMap.remove(position); 
     super.destroyItem(container, position, object); 
    } 


    public EventListFragment getFragment(int key) { 
     Log.i(TAG, "Size of pager references: "+mPageReferenceMap.size()); 
     return mPageReferenceMap.get(key); 
    } 
} 

Il problema è che il destroyItem() viene chiamato più spesso di quanto getItem(), quindi sono lasciati con riferimenti nulli. Se non utilizzo destroyItem() per cancellare i riferimenti ai frammenti distrutti ... beh, faccio riferimento a frammenti che non esistono.

C'è un bel modo per fare riferimento a frammenti che vengono creati con EventListFragment mFragment = EventListFragment.newInstance(dateOffset);? O cosa devo fare per aggiornare un frammento all'interno di un ViewPager dalla mia attività (dal menu delle opzioni per essere precisi)?

risposta

5

Sono riuscito a risolverlo. Il trucco consisteva nel creare una lista di riferimento all'interno di Activity, non in PagerAdapter. Va in questo modo:

List<WeakReference<EventListFragment>> fragList = new ArrayList<WeakReference<EventListFragment>>(); 

@Override 
public void onAttachFragment (Fragment fragment) { 
    Log.i(TAG, "onAttachFragment: "+fragment); 
    if(fragment.getClass()==EventListFragment.class){ 
     fragList.add(new WeakReference<EventListFragment>((EventListFragment)fragment)); 
    } 
} 
public EventListFragment getFragmentByPosition(int position) { 

    EventListFragment ret = null; 
    for(WeakReference<EventListFragment> ref : fragList) { 
     EventListFragment f = ref.get(); 
     if(f != null) { 
      if(f.getPosition()==position){ 
       ret = f; 
      } 
     } else { //delete from list 
      fragList.remove(f); 
     } 
    } 
    return ret; 

} 

Naturalmente la frammento deve implementare una funzione getPosition(), ma avevo bisogno di qualcosa di simile a questo comunque, quindi non era un problema.

Grazie Alex Lockwood per il suggerimento con WeakReference!

+0

Ho appena finito le mie finali e ho deciso di tornare e vedere se le cose funzionavano ... felice di essere stato in grado di aiutare (anche se non era il problema principale: P). –

+0

Domanda: la chiamata a fragList.remove() non deve essere passata al riferimento debole, piuttosto che al frammento? – gcl1

+0

@ Michael: Ho iniziato a utilizzare un approccio come questo, e funziona piuttosto bene. Ma dal momento che il fragList contiene riferimenti deboli, sembra che le voci siano soggette alla garbage collection, anche se potrebbero comunque averne bisogno. Ho visto che il metodo getFragmentByPosition() a volte restituisce null, quindi penso che sia quello che sta succedendo. Qualche idea su come aggirare questo? Grazie. – gcl1

3

Due cose:

  1. aggiungere la seguente riga nel metodo di attività onCreate (o dovunque si inizializza la tua ViewPager):

    mPager.setOffscreenPageLimit(NUM_ITEMS-1); 
    

    Ciò manterrà le pagine aggiuntive off-screen in memoria (cioè impedendo che vengano distrutti), anche quando non sono attualmente mostrati sullo schermo.

  2. Si potrebbe considerare di implementare la HashMap in modo che tenga WeakReference<Fragment> s invece dei Fragment stessi s. Si noti che ciò richiederebbe di modificare il metodo di getFragment come segue:

    WeakReference<Fragment> weakRef = mPageReferenceMap.get(position); 
    return (weakRef != null) ? weakRef.get() : null; 
    

    Questo non ha nulla a che fare con il problema ... è solo qualcosa che ho notato e ho pensato di portare alla vostra attenzione. Mantenere WeakReferences ai tuoi Fragment s vi permetterà di sfruttare la capacità del garbage collector per determinare raggiungibilità per voi, in modo che non c'è bisogno di farlo da soli.

+0

Per quanto riguarda il 2. => che verrà non risolvere il mio problema, ma è probabilmente una buona idea per evitare perdite, grazie. E 1. => Avrò 7 pagine, forse più in futuro, è tutto ok per tenerle tutte in memoria allo stesso tempo? –

+0

Hmm ... beh, ovviamente meno "Frammenti" che stai conservando in memoria meglio è. Se vuoi accedere al tuo 'Fragment's on demand dal tuo' Activity' (senza effettivamente passare alla pagina 'Fragment's) senza tenerli tutti in memoria, la correzione sarebbe più complicata. Potrebbe richiedere di scavare nel codice sorgente di 'ViewPager' e vedere come gestisce il ciclo di vita di' Fragment'. Non sono a conoscenza di alcun modo per farlo, ma cercherò di approfondirlo quando avrò più tempo. –

+0

Posso umilmente suggerire, se c'è qualcosa che è necessario per ottenere da un frammento mentre è fuori campo, forse non dovrebbe essere dando a un frammento.Considera di metterlo in un servizio o ContentProvider e lasciare che il tuo frammento sia un client. – Sparky

Problemi correlati