2013-08-14 21 views
20

Ho un'attività che contiene un View Pager che ha un adattatore FragmentStatePagerAdapter. ogni volta che si immette l'attività occuperà 200mb di memoria, dopo essere uscito dall'attività (fine()) e quindi reinserendolo, si aggiungerà e raddoppierà la memoria utilizzata sul telefono.I frammenti non vengono rilasciati dalla memoria

Dopo aver risolto il problema, sembra che il gestore dei frammenti non stia rilasciando i frammenti anche se sto cercando di rimuoverli ma non funziona.

Ho provato a svuotare il frammento che viene aggiunto per assicurarsi che non sia qualcosa di interno all'interno del frammento, il problema rimane.

mio codice adattatore è

private class ChildrenPagerAdapter extends FragmentStatePagerAdapter 
    { 
     private List<ChildBean> childrenBean; 

     public ChildrenPagerAdapter(FragmentManager fm, List<ChildBean> bean) 
     { 
     super(fm); 
     this.childrenBean = bean; 
     } 

     @Override 
     public int getItemPosition(Object object) 
     { 
     return PagerAdapter.POSITION_NONE; 
     } 

     @Override 
     public Fragment getItem(int position) 
     { 

     ReportFragment reportFragment = new ReportFragment(); 
     reportFragment.childBean = childrenBean.get(position); 
     reportFragment.position = position; 
     reportFragment.mPager = mPager; 
     if(position == 0) 
     { 
      reportFragment.mostLeft = true; 
     } 
     if(position == childrenNumber - 1) 
     { 
      reportFragment.mostRight = true; 
     } 

     return reportFragment; 
     } 

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

     @Override 
     public void destroyItem(ViewGroup container, int position, Object object) 
     { 
     // TODO Auto-generated method stub 
     super.destroyItem(container, position, object); 
     } 
    } 

mio codice attività è il codice

public class ReportActivity extends CustomActivity 
{ 
    public ImageLoader imageLoader; 
    private ViewPager mPager; 
    private PagerAdapter mPagerAdapter; 
    private int childrenNumber; 
    private int currentChild; 

    @Override 
    protected void onDestroy() 
    { 
     mPager.removeAllViews(); 
     mPager.removeAllViewsInLayout(); 
     mPager.destroyDrawingCache(); 
     mPagerAdapter = null; 
     mPager = null; 
     System.gc(); 
     super.onDestroy(); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 

     super.onCreate(savedInstanceState); 
     setCustomTitle(string.title_activity_reports); 
     this.currentChild = getIntent().getIntExtra("itemselected", -1); 

     getSupportFragmentManager(). 
    } 

    @Override 
    protected void onResume() 
    { 
     super.onResume(); 
     mPager = (ViewPager) findViewById(R.id.vpchildren); 
     mPager.setOffscreenPageLimit(6); 
     childrenNumber = MainActivity.bean.size(); 
     mPagerAdapter = new ChildrenPagerAdapter(getSupportFragmentManager(), MainActivity.bean); 
     mPager.setAdapter(mPagerAdapter); 
     mPager.setCurrentItem(currentChild); 
    } 
} 

Frammento:

public class ReportFragment extends Fragment 
{ 

    public ChildBean childBean; 
    public int position; 
    public ImageView img; 
    public ImageLoader imageLoader; 
    public DisplayImageOptions options; 
    private int pee = 0; 
    private int poop = 0; 
    private double sleep = 0.0; 
    public ViewPager mPager; 
    public boolean mostLeft = false; 
    public boolean mostRight = false; 

    public ReportFragment() 
    { 

    } 

    @Override 
    public void onDestroyView() 
    { 
     super.onDestroyView(); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    { 
     ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.report_fragment, container, false); 

     if(mostLeft) 
     { 
     rootView.findViewById(id.btnleft).setVisibility(View.GONE); 
     } 
     if(mostRight) 
     { 
     rootView.findViewById(id.btnright).setVisibility(View.GONE); 
     } 

     rootView.findViewById(id.btnleft).setOnClickListener(new OnClickListener() 
     { 

     @Override 
     public void onClick(View v) 
     { 
      mPager.setCurrentItem(mPager.getCurrentItem() - 1); 

     } 
     }); 

     rootView.findViewById(id.btnright).setOnClickListener(new OnClickListener() 
     { 

     @Override 
     public void onClick(View v) 
     { 
      mPager.setCurrentItem(mPager.getCurrentItem() + 1); 

     } 
     }); 

     SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH); 
     Date dobchild = new Date(); 

     ((TextView) rootView.findViewById(id.tvday)).setText(sdf.format(dobchild)); 

     ImageView childimg = (ImageView) rootView.findViewById(id.img_child); 
     ((TextView) rootView.findViewById(id.tvchildname)).setText(childBean.childname); 
     ((TextView) rootView.findViewById(id.tvclassname)).setText(((CustomApplication) getActivity().getApplication()).preferenceAccess.getCurrentClassName()); 

     Date dob = null; 
     String age = ""; 
     try 
     { 
     dob = sdf.parse(childBean.childdob); 
     age = GeneralUtils.getAge(dob.getTime(), getString(string.tv_day), getString(string.tv_month), getString(string.tv_year)); 
     } 
     catch(ParseException e) 
     { 
     // TODO: 
     } 
     ((CustomTextView) rootView.findViewById(id.tvchildage)).setText(age); 

     DisplayImageOptions options = 
     new DisplayImageOptions.Builder().showImageForEmptyUri(drawable.noimage).showImageOnFail(drawable.noimage).showStubImage(drawable.noimage).cacheInMemory() 
      .imageScaleType(ImageScaleType.NONE).build(); 

     imageLoader = ImageLoader.getInstance(); 
     imageLoader.displayImage(childBean.childphoto, childimg, options); 
     final TextView tvpee = (TextView) rootView.findViewById(id.tvpeetime); 
     final TextView tvpoop = (TextView) rootView.findViewById(id.tvpootimes); 
     final TextView tvsleep = (TextView) rootView.findViewById(id.tvsleeptime); 

     rootView.findViewById(id.btnaddpee).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      pee = pee + 1; 
      if(pee > 9) 
      { 
       Toast.makeText(getActivity(), getString(string.tvareyousurepee), Toast.LENGTH_LONG).show(); 
      } 
      tvpee.setText(String.format(getString(string.tvtimes), pee)); 
     } 
     }); 

     rootView.findViewById(id.btnminuspee).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      if(pee > 0) 
      { 
       pee = pee - 1; 
       tvpee.setText(String.format(getString(string.tvtimes), pee)); 
      } 
     } 
     }); 

     rootView.findViewById(id.btnpluspoo).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      poop = poop + 1; 
      if(poop > 9) 
      { 
       Toast.makeText(getActivity(), getString(string.tvareyousurepoop), Toast.LENGTH_LONG).show(); 
      } 
      tvpoop.setText(String.format(getString(string.tvtimes), poop)); 
     } 
     }); 

     rootView.findViewById(id.btnminuspoo).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      if(poop > 0) 
      { 
       poop = poop - 1; 
       tvpoop.setText(String.format(getString(string.tvtimes), poop)); 
      } 
     } 
     }); 

     rootView.findViewById(id.btnaddsleep).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      sleep = sleep + 0.25; 
      tvsleep.setText(String.format(getString(string.tvhours), sleep)); 
     } 
     }); 

     rootView.findViewById(id.btnminussleep).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      if(sleep > 0) 
      { 
       sleep = sleep - 0.25; 
       tvsleep.setText(String.format(getString(string.tvhours), sleep)); 
      } 
     } 
     }); 

     rootView.findViewById(id.btnsave).setOnClickListener(new OnClickListener() 
     { 
     @Override 
     public void onClick(View v) 
     { 
      Toast.makeText(getActivity(), "Report Saved.", Toast.LENGTH_LONG).show(); 
      getActivity().finish(); 
     } 
     }); 

     return rootView; 
    } 
} 

Si prega di avvisare ... Grazie

+1

puoi pubblicare il codice di ReportFragment? – Henrique

+0

@Henrique fatto, grazie –

+1

La tua app richiede davvero 200mb? 'FragmentStatePagerAdapter' è utilizzato per l'efficienza per mantenere la più piccola quantità di frammenti in memoria. Nella tua app, tuttavia, stai andando controcorrente usando 'mPager.setOffscreenPageLimit (6) ;, fondamentalmente mantenendo in memoria un massimo di 13 frammenti. – Luksprog

risposta

21

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.

Prima di tutto guardando il tuo codice Non ti vedo alcuna misura di rilascio della memoria nei tuoi frammenti suDestroy(). Il fatto che il frammento stesso sia distrutto e gc'ed non significa che tutte le risorse che hai assegnato siano state rimosse.

Per esempio, la mia grande preoccupazione è:

imageLoader = ImageLoader.getInstance(); 
imageLoader.displayImage(childBean.childphoto, childimg, options); 

Da quello che vedo qui sembra che non ci sia un'istanza statica di ImageLoader che viene infilò ogni volta che appare un nuovo frammento, ma non riesco a vedere dove un frammento morente chiederebbe a ImageLoader di scaricare la sua roba. Mi sembra sospetto.

Se fossi in te, eseguirò il dump di un file HPROF della mia applicazione nel momento in cui sono stati necessari 200mb extra (come richiesto) dopo il riavvio dell'attività e l'analisi dei 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.

3

Non memorizzare riferimenti "forti" a ViewPager o ImageView nel frammento. Stai creando un riferimento ciclico che manterrà tutto in memoria. Invece, se è necessario mantenere un riferimento alla ViewPager o qualsiasi altro elemento che fa riferimento il suo contesto al di fuori della vostra attività, provare a utilizzare un WeakReference, ad esempio:

private WeakReference<ViewPager> mPagerRef; 
... 
mPagerRef = new WeakReference<ViewPager>(mPager); 
... 
final ViewPager pager = mPagerRef.get(); 

if (pager != null) { 
    pager.setCurrentItem(...); 
} 

seguito di questo modello con gli oggetti che memorizzano un riferimento al Il contesto di attività o applicazione (suggerimento: qualsiasi ViewGroup, ImageView, Activity, ecc.) Dovrebbe impedire che si verifichino "perdite di memoria" sotto forma di "cicli di conservazione".

+0

Puoi fornire un esempio dove questo sarebbe preferibile? Per ogni vista in ogni frammento? –

1

Dopo aver utilizzato lo strumento dell'analizzatore di memoria in eclissi ho scoperto che ciò che è rimasto nella memoria è il layout effettivo dei miei frammenti. Layout relativo in specifico.

Il motivo di ciò è un CustomTextView che ho creato con un set di caratteri personalizzato come carattere tipografico.

Typeface face=Typeface.createFromAsset(context.getAssets(), "Helvetica_Neue.ttf"); 
this.setTypeface(face); 

Per risolvere la perdita di memoria ho semplicemente fatto la seguente risposta trovato here:

public class FontCache { 

    private static Hashtable<String, Typeface> fontCache = new Hashtable<String, Typeface>(); 

    public static Typeface get(String name, Context context) { 
     Typeface tf = fontCache.get(name); 
     if(tf == null) { 
      try { 
       tf = Typeface.createFromAsset(context.getAssets(), name); 
      } 
      catch (Exception e) { 
       return null; 
      } 
      fontCache.put(name, tf); 
     } 
     return tf; 
    } 
} 
+1

E pensi che la risposta inaccettabile che ti ha dato le indicazioni giuste (MAT) e le informazioni siano appropriate? – EvilDuck

+0

no hai ragione la mia brutta notizia che non si è accorta la tua risposta –

Problemi correlati