¿Cómo puedo cambiar entre dos fragmentos, sin recrear los fragmentos cada vez?

Estoy trabajando en una aplicación de Android, que utiliza un cajón de navegación para cambiar entre dos fragmentos. Sin embargo, cada vez que cambio, el fragmento es completamente recreado.

Aquí está el código de mi actividad principal.

/* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } private void selectItem(int position) { android.support.v4.app.Fragment fragment; String tag; android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager(); switch(position) { case 0: if(fragmentManager.findFragmentByTag("one") != null) { fragment = fragmentManager.findFragmentByTag("one"); } else { fragment = new OneFragment(); } tag = "one"; break; case 1: if(fragmentManager.findFragmentByTag("two") != null) { fragment = fragmentManager.findFragmentByTag("two"); } else { fragment = new TwoFragment(); } tag = "two"; break; } fragment.setRetainInstance(true); fragmentManager.beginTransaction().replace(R.id.container, fragment, tag).commit(); // update selected item and title, then close the drawer mDrawerList.setItemChecked(position, true); setTitle(mNavTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } 

He configurado algún registro de depuración, y cada vez que selectItem se llama, un fragmento se destruye, mientras que el otro se crea.

¿Hay alguna manera de evitar que los fragmentos de ser recreado, y sólo reutilizar en su lugar?

Después de @meredrica señaló que replace () destruye los fragmentos, volví a través de la documentación de FragmentManager. Esta es la solución que he creado, que parece estar funcionando.

 /* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } private void selectItem(int position) { android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager(); switch(position) { case 0: if(fragmentManager.findFragmentByTag("one") != null) { //if the fragment exists, show it. fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("one")).commit(); } else { //if the fragment does not exist, add it to fragment manager. fragmentManager.beginTransaction().add(R.id.container, new OneFragment(), "one").commit(); } if(fragmentManager.findFragmentByTag("two") != null){ //if the other fragment is visible, hide it. fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("two")).commit(); } break; case 1: if(fragmentManager.findFragmentByTag("two") != null) { //if the fragment exists, show it. fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("two")).commit(); } else { //if the fragment does not exist, add it to fragment manager. fragmentManager.beginTransaction().add(R.id.container, new TwoFragment(), "two").commit(); } if(fragmentManager.findFragmentByTag("one") != null){ //if the other fragment is visible, hide it. fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("one")).commit(); } break; } // update selected item and title, then close the drawer mDrawerList.setItemChecked(position, true); setTitle(mNavTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } 

También he añadido este poco, pero no estoy seguro si es necesario o no.

 @Override public void onDestroy() { super.onDestroy(); FragmentManager fragmentManager = getSupportFragmentManager(); if(fragmentManager.findFragmentByTag("one") != null){ fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("one")).commit(); } if(fragmentManager.findFragmentByTag("two") != null){ fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("two")).commit(); } } 

Utilice el método attach / detach con las etiquetas:

Detach destruirá la vista hirachy pero mantiene el estado, como si en la backstack; Esto permitirá que el fragmento "no visible" tenga una huella de memoria menor. Pero ten en cuenta que necesitas implementar correctamente el ciclo de vida de los fragmentos (lo que deberías hacer en primer lugar)

Quite el fragmento dado de la interfaz de usuario. Este es el mismo estado que cuando se coloca en la pila posterior: el fragmento se quita de la interfaz de usuario, sin embargo, su estado sigue siendo gestionado activamente por el gestor de fragmentos. Al entrar en este estado su jerarquía de vista es destruida.

La primera vez que agregue el fragmento

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.add(android.R.id.content, new MyFragment(),MyFragment.class.getSimpleName()); t.commit(); 

Luego lo desacoplas

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.detach(MyFragment.class.getSimpleName()); t.commit(); 

Y volver a conectarlo si se cambia de nuevo, el estado se mantendrá

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName())); t.commit(); 

Pero siempre tienes que comprobar si el fragmento se ha añadido aún, si no, añádalo, sino simplemente adjúntelo:

 if (getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()) == null) { FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.add(android.R.id.content, new MyFragment(), MyFragment.class.getSimpleName()); t.commit(); } else { FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName())); t.commit(); } 

El método replace reemplaza tus fragmentos. Una solución es configurarlos con Visibility.GONE , otro método (menos fácil) es mantenerlos en una variable. Si lo hace, asegúrese de no perder el espacio de memoria a la izquierda y la derecha.

Hice esto antes así:

  if (mPrevFrag != fragment) { // Change FragmentTransaction ft = fragmentManager.beginTransaction(); if (mPrevFrag != null){ ft.hide(mPrevFrag); } ft.show(fragment); ft.commit(); mPrevFrag = fragment; } 

(Usted necesitará rastrear su fragmento permeable en esta solución)

Supongo que no puedes manipular directamente los mecanismos del ciclo de vida de tus Fragments . El hecho de que usted puede findFragmentByTag no es muy malo. Significa que el objeto Fragmento no se recrea completamente, si ya está comprometido. El Fragment existente sólo pasa todos los pasos del ciclo de vida de cada Fragment tiene – lo que significa que sólo la interfaz de usuario es "recreado".

Es una estrategia de gestión de memoria muy conveniente y útil – y apropiada, en la mayoría de los casos. Fragment que se ha ido, tiene los recursos que tienen que ser utilizados con el fin de desasignar la memoria.

Si acaba de dejar de usar esta estrategia, el uso de memoria de su aplicación podría aumentar mal.

Sin embargo, hay fragmentos retenidos , cuyo ciclo de vida es un poco diferente y no corresponden a la Actividad a la que están vinculados. Normalmente, se utilizan para retener algunas cosas que desea guardar, por ejemplo, para administrar cambios de configuración

Sin embargo, la estrategia de creación de fragmentos depende de su contexto, es decir, de lo que le gustaría resolver y de los compromisos que está dispuesto a aceptar.

Esta es una respuesta poco tarde. Si está utilizando el paginador de vista para fragmentos, establezca el límite de página de pantalla del fragmento en el número de fragmentos creados.

 mViewPager.setOffscreenPageLimit(3); // number of fragments here is 3 

La misma idea que Tester101 pero esto es lo que terminé usando.

  FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); Fragment oldFragment = fragmentManager.findFragmentByTag( "" + m_lastDrawerSelectPosition ); if ( oldFragment != null ) fragmentTransaction.hide( oldFragment ); Fragment newFragment = fragmentManager.findFragmentByTag( "" + position ); if ( newFragment == null ) { newFragment = getFragment( position ); fragmentTransaction.add( R.id.home_content_frame, newFragment, "" + position ); } fragmentTransaction.show( newFragment ); fragmentTransaction.commit(); 

¿Qué tal jugar con el atributo Visible?

  • Diseño de Android con barra de acciones y pestañas
  • Cómo obtener la vista de un fragmento fuera de OnCreateView ()
  • Fragmento de Android: findViewById devuelve null
  • Fragmentos dentro de ViewPager no se destruyen
  • FragmentManager y SupportFragmentManager ambos utilizados
  • Seleccione la imagen de la galería en Android Fragment
  • Actividad de inicio de Fragmento causa NullPointerException
  • DialogFragment setMessage con una nueva línea
  • Fragmento pila trasera no funciona cuando se extiende AppCompatActivity
  • Fragmentos y actividades - ¿dónde pongo la lógica de mi aplicación?
  • Cómo agregar un fragmento a un diseño de un DialogFragment?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.