Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Los fragmentos no se liberan de la memoria

Tengo una actividad que contiene un View Pager que tiene un adaptador FragmentStatePagerAdapter. Cada vez que entra en la actividad que ocupará 200mb de memoria, después de volver a salir de la actividad (finish ()) y luego volver a entrar en él se anexará y el doble de la memoria utilizada en el teléfono.

Después de solucionar el problema, parece como si el gestor de fragmentos no está liberando los fragmentos, aunque estoy tratando de eliminarlos, pero su simplemente no funciona.

Traté de vaciar el fragmento que se está añadiendo para asegurarse de que no es algo interno dentro del fragmento del problema sigue siendo.

Mi código del adaptador es

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

Mi código de actividad es

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

Código fragmento:

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

Por favor asesóreme, gracias

  • Multiple AsyncTaskLoader en una sola actividad - ¿tiene que ser inicializado cada cargador en onCreate?
  • Android - Backstack al reemplazar el fragmento en ViewPager
  • ¿Es posible hacer esta animación de pantalla Android con un ViewPager?
  • Depth Pager Transformer igual que SnapChat
  • Desactivación de la animación en ViewPager
  • Fragmento anterior visible bajo el nuevo fragmento
  • Cómo deshabilitar el adaptador viewpager al tocar vistas específicas?
  • Vista en el paginador de vistas superposición entre vistas anterior y siguiente
  • 4 Solutions collect form web for “Los fragmentos no se liberan de la memoria”

    ViewPager tiene un método setOffscreenPageLimit que le permite especificar el número de páginas guardadas por el adaptador. Así que sus fragmentos que están lejos serán destruidos.

    En primer lugar mirando a su código no veo hacer ninguna memoria liberando medidas en sus fragmentos onDestroy (). El hecho de que el fragmento es destruido y gc'ed no significa que todos los recursos que asignó fueron eliminados también.

    Por ejemplo, mi gran preocupación es:

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

    Por lo que veo aquí parece que hay una instancia estática de ImageLoader que se empuja cada vez que aparece un nuevo fragmento, pero no puedo ver donde un fragmento moribundo le pedirá a ImageLoader que descargue sus cosas. Eso me parece sospechoso.

    Si estuviera usted me volcaría un archivo HPROF de mi aplicación en el momento en que tomó 200 MB adicionales (como usted dice) después de la actividad de reinicio y analizar las referencias a través de MAT (herramienta de analizador de memoria). Usted está claramente teniendo problemas de fugas de memoria y dudo mucho que el problema está en Fragmentos en sí no ser destruido.

    En caso de que no sepa cómo analizar el montón de memoria, aquí hay un buen video . No puedo contar cuántas veces me ayudó a identificar y eliminar las pérdidas de memoria en mis aplicaciones.

    No guarde referencias "fuertes" a ViewPager o ImageView en su Fragmento. Estás creando una referencia cíclica que mantendrá todo en la memoria. En su lugar, si debe mantener una referencia a ViewPager o cualquier otro elemento que haga referencia a su contexto fuera de su actividad, intente usar una WeakReference, por ejemplo:

     private WeakReference<ViewPager> mPagerRef; ... mPagerRef = new WeakReference<ViewPager>(mPager); ... final ViewPager pager = mPagerRef.get(); if (pager != null) { pager.setCurrentItem(...); } 

    Siguiendo este patrón con Objetos que almacenan una referencia al contexto Actividad o Aplicación (sugerencia: cualquier ViewGroup, ImageView, Actividad, etc.) deben evitar que se produzcan "pérdidas de memoria" en forma de "retener ciclos".

    Parece que su código no está destruyendo la vista, compruebe este elemento Destruir desde el adaptador de ViewPager podría resolver este problema.

    Después de usar la herramienta del analizador de memoria en eclipse me enteré de que lo que se pegue en mi memoria es el diseño real de mis fragmentos. Disposición relativa en específico.

    La razón de esto es un CustomTextView que he creado que tiene un conjunto de fuentes personalizado como un tipo de letra.

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

    Para solucionar la pérdida de memoria simplemente hice la siguiente respuesta encontrada aquí :

     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; } } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.