2013-06-06 14 views
29

Voglio realizzare questo: enter image description here
Io uso un ViewPager con un FragmentStatePagerAdapter.
Ho iniziato con l'esempio da questa pagina:
http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.htmlCome distruggere i vecchi frammenti in FragmentStatePagerAdapter

Questo è il mio adattatore ViewPager:

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); 
     } 

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

Ogni pagina del mio ViewPager contiene un ListView con alcuni dati. Nel momento in cui passo a una nuova pagina in ViewPager aumenterà la memoria RAM molto rapidamente.
Come rimuovere i vecchi frammenti?
Ho anche usato questo, ma non fa nulla:

public void destroyItem(ViewGroup container, int position, Object object) { 

    FragmentManager manager = ((Fragment) object).getFragmentManager(); 
    FragmentTransaction trans = manager.beginTransaction(); 
    trans.remove((Fragment) object); 
    trans.commit(); 

    super.destroyItem(container, position, object); 
} 

C'è anche un ritardo di 1-2 secondi dopo che ho passare rapidamente a una nuova pagina o una pagina vecchia. C'è qualche tecnica per rimuovere quel ritardo. Se passo a una nuova pagina e aspetto 2 secondi, al prossimo passaggio non ci sono più ritardi.

Testato su Nexus 7.

+0

Hai trovato soluzioni? –

+0

si prega di fornire la soluzione @vovahost – jyomin

risposta

12

Non si dovrebbe cercare di interferire con il modo in cui Android gestisce le implementazioni Fragment.Il valore predefinito per setOffScreenPageLimit dovrebbe essere già uno. Ciò significa che Android distruggerà i vecchi frammenti quando la memoria si esaurisce. Finché non hai un problema di memoria, lascia stare.

Il motivo per cui la memoria aumenta è perché Android mantiene le istanze Fragment in memoria per poter riconnettersi a loro invece di dover istanziarle. Ti consiglio di tenere conto della contingenza delle tue istanze Fragment distrutte dal sistema operativo, salvandone il loro stato se ciò accade e lasciare che il sistema operativo faccia il suo lavoro.

Il ritardo che si verifica potrebbe essere dovuto a un calcolo intensivo sul thread dell'interfaccia utente. Se lo è, suggerisco di trasferirlo a, ad esempio, un AsyncTask. Senza il codice, tuttavia, è solo un'ipotesi su cosa potrebbe causare il problema. Ma il solo ritardo iniziale suggerisce che stai caricando qualcosa che potrebbe bloccare il thread dell'interfaccia utente.

Aggiornamento: Date un'occhiata al https://stackoverflow.com/a/9646622/170781 che delinea molto ordinatamente come il ViewPager gestisce Fragment istanze.

+1

ohhh appena setOffScreenPageLimite salvami ... ho avuto 4 schede di frammento quando mi muovo dall'1 al 4 e dal 4 al 1 rimuove tutti i dati ma setOffscreenLimte ripristina quello stato Grazie a lottttttttttttttt ... – CoronaPintu

+0

Hai ragione. C'era qualche problema con il calcolo sul thread UI – vovahost

+0

Contento di aver potuto aiutare! – Eric

3

Il FragmentStatePagerAdapter è già molto frugale con la memoria in quanto distrugge la vostra non necessari fragments automaticamente. Mantiene solo le viste dei frammenti direttamente a sinistra e a destra dell'elemento attualmente mostrato e distrugge gli altri.

Esempio: Quindi una volta che Swipe per giusta direzione, è pre-carica i ben presto di essere di destra-prossimo-frammento e distrugge il frammento che ora è due slot a sinistra del frammento correntemente visualizzata.

+1

La memoria sembra sempre accumularsi, quello che stai dicendo è teoricamente giusto, ma non sta accadendo. –

+0

stai caricando 50mb-bitmap con 33k-modem allora? :) non ho mai visto un comportamento del genere quando uso la FSPA. – bofredo

+1

So di cosa sto parlando non ti preoccupare, ecco un codice di riferimento che ho postato puoi vedere per te stesso la memoria accumulata. http://stackoverflow.com/questions/18241433/fragments-are-not-being-released-from-memory –

1

Penso che il problema non sia con ViewPager in ListFragments. Che tipo di contenuti mostri su di loro? Alloca molte immagini? Puoi pubblicare il codice del tuo ListFragment?

Preferirei fare un commento ma poiché non ho abbastanza punti spero di aiutare modificando questa risposta.

1

ViewPager ha un metodo setOffscreenPageLimit che consente di specificare il numero di pagine conservate dall'adattatore. Quindi i tuoi frammenti che sono lontani saranno distrutti.

È un po 'difficile dire quale potrebbe essere il tuo particolare problema perché non so cosa fa il tuo frammento. Con il suono di 1-2 secondi di ritardo sembra che si stia lavorando sul thread dell'interfaccia utente. Inoltre che altro stai facendo nel tuo frammento che consuma la memoria? Forse stai caricando le immagini su qualche cache di memoria statica e non le stai liberando alla rimozione dei frammenti? Potresti fornire il codice del tuo frammento, così ho potuto vedere cosa sta facendo?

In generale, suggerirei di scaricare un file HPROF dell'applicazione nel momento in cui è necessaria memoria aggiuntiva e analizzare i riferimenti tramite MAT (strumento di analisi della memoria). Si sta chiaramente avendo problemi di perdite di memoria e dubito fortemente che il problema non sia stato distrutto da Fragments.

Nel caso in cui non si sappia come analizzare l'heap di memoria, ecco un buon video. Non riesco a contare quante volte mi ha aiutato a identificare e eliminare le perdite di memoria nelle mie app.

12

Ho avuto lo stesso problema. Ma nel mio caso ViewPager era all'interno di un altro frammento. e dopo aver rimosso ViewPagerFragment da FragmentManager, tutti i frammenti di FragmentStatePagerAdapter rimangono in Gestione frammenti. quindi, dopo alcuni di questi cambiamenti, era OutOfMemoryError. Poi accendo su tronchi FragmentManager da:

FragmentManager.enableDebugLogging(true); 

e ha scoperto che id di ogni nuovo porta ad una crescita frammento ogni volta. Si verifica solo con StatePagerAdapter. Per risolvere questo problema chiamo rimuovere per ogni frammento che è stato istanziato.

protected void dispatchOnDetach(Iterable<Fragment> fragments) { 
    if (fragments == null) 
     return; 

    Activity aa = getActivity(); 
    if (aa == null) 
     return; 

    IBaseActivity ba = (IBaseActivity) aa; 
    if (ba.isActivityStopped()) 
     return; 

    FragmentManager frMan = ba.getSupportFragmentManager(); 
    FragmentTransaction frTr = frMan.beginTransaction(); 

    for (Fragment fr : fragments) { 
     if (fr != null) { 
      frTr.remove(fr); 
     } 
    } 

    frTr.remove(this); 
    frTr.commit(); 

} 

Nel tuo caso. se non si modifica ViewPager durante il runtime, è possibile che il garbage collector non possa distruggere i frammenti anche dopo averli rimossi dal gestore dei frammenti a causa di alcuni riferimenti ad essi. Dovresti controllare se alcune classi globali li usano.

E per scopi di ottimizzazione è possibile memorizzare nella cache ogni frammento istanziato utilizzando SoftReference o LruCache. Esempio:

public class MyAdapter extends FragmentStatePagerAdapter { 

private final LruCache<Integer, Fragment> mCache; 

public MyAdapter(FragmentManager fm) { 
    super(fm); 
    mCache = new LruCache<Integer, Fragment>(10); 
} 

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

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

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

private class MyCache extends LruCache<Integer, Fragment> { 

    public MyCache(int maxSize) { 
     super(maxSize); 
    } 

    @Override 
    protected Fragment create(Integer key) { 
     return ArrayListFragment.newInstance(key); 
    } 
} 
} 
+0

Dove si chiama esattamente la rimozione sui frammenti istanziati, per favore? –

+0

In onDetachMethod. – akelix

1

Ignorare questo in FragmentStatePagerAdapter, notare la leggera modifica.

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    if (position >= getCount()) { 
    FragmentManager manager = ((Fragment) object).getFragmentManager(); 
    FragmentTransaction trans = manager.beginTransaction(); 
    trans.remove((Fragment) object); 
    trans.commit(); 
} 
Problemi correlati