¿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.
- FragmentPagerAdapter sólo existe en Android.Support.V4.App (y no en Android.App)
- Obtener imagen de la galería para establecer en imageview en fragmento?
- NavigationView cómo manejar contenido de encabezado dinámico
- android getSupportActionBar () devuelve null en el fragmento
- Orden de transacciones de fragmentos múltiples de Android
/* 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?
- Ver reutilización en fragmentos android
- ¿Cómo puedo habilitar las pestañas de la barra de acciones en un fragmento?
- Eliminación del fragmento haciendo clic / tocando fuera:
- Cómo reproducir un video con la API de YouTube mediante YouTubePlayerFragment?
- DialogFragment bloquea la aplicación en el cambio de orientación
- SetTitle cuando el fragmento es visible nuevamente
- Manejo de barras de acción con dos fragmentos
- cómo hacer clic en el botón de acción flotante en un fragmento?
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?
- Cómo agregar sombra a TextView en la selección / enfoque
- Android, cómo desenfocar / vidrio / helada actividad actual