2011-05-31 10 views
14

¿es posible cambiar de Fragmentos sin volver a crearlos todo el tiempo? ¿Si es así, cómo?Android Honeycomb: ¿Cómo cambiar Fragmentos en FrameLayout, sin volver a crearlos?

In the documentation Encontré un ejemplo de cómo reemplazar Fragmentos.

// Create new fragment and transaction 
Fragment newFragment = new ExampleFragment(); 
FragmentTransaction transaction = getFragmentManager().beginTransaction(); 

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

// Commit the transaction 
transaction.commit(); 

Pero no quiero crear mis fragmentos del cero cada vez que los necesite.

También encontré this example de ocultar/mostrar fragmentos:

// The content view embeds two fragments; now retrieve them and attach 
// their "hide" button. 
FragmentManager fm = getFragmentManager(); 
addShowHideListener(R.id.frag1hide, fm.findFragmentById(R.id.fragment1)); 
addShowHideListener(R.id.frag2hide, fm.findFragmentById(R.id.fragment2)); 

Pero ¿cómo iba a crear un fragmento con un ID fuera de un archivo XML?

Creo que esto podría estar relacionado con this question, pero no hay una respuesta. :/

Muchas gracias por adelantado, medusas

Editar:

Eso es como lo estoy haciendo ahora:

Fragment shown = fragmentManager.findFragmentByTag(shownFragment); 

//... 

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
if (shown != null) fragmentTransaction.hide(shown); 

//switch statetement for menu selection, just one example: 

SettingsFragment set = (SettingsFragment) fragmentManager.findFragmentByTag(SET); 
Toast.makeText(this, "Settings:" + set, Toast.LENGTH_LONG).show(); 
if (set == null) 
{ 
     set = new SettingsFragment(); 
     fragmentTransaction.add(R.id.framelayout_content, set, SET); 
} 
else fragmentTransaction.show(set); 
shownFragment = SET; 
fragmentTransaction.commit(); 

Si llamo a los ajustes, luego otra cosa, y luego volver a la configuración, la tostada me da "nulo" primero y "Configuración: Fragmento de configuración {40ef ..." segundo.

Sin embargo, si reemplazo fragmentTransaction.add(R.id.framelayout_content, set, SET); con fragmentTransaction.replace(R.id.framelayout_content, set, SET); sigo recibiendo "nulo", "nulo", "nulo" ... por lo que no parece encontrar el fragmento por etiqueta.

Edit2:

Adición fragmentTransaction.addToBackStack(null); hizo el truco. :) Esto ahorra todo el ocultamiento/memorización del fragmento que se muestra como parte, así que supongo que es la solución más elegante para esto.

Encontré this tutorial bastante útil sobre el tema.

Edit3:

En cuanto a mi código me di cuenta que podía deshacerse de algunas partes, por lo que cambió a:

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 
if (shown != null) fragmentTransaction.hide(shown); 
Settings set = (Settings) fragmentManager.findFragmentByTag(SET); 
if (set == null) set = new Settings(); 

fragmentTransaction.replace(R.id.framelayout_content, set, SET); 
fragmentTransaction.addToBackStack(null); 
fragmentTransaction.commit(); 

Sin embargo, este invoca un IllegalStateException: Fragment already added, casi de la misma como here. ¿Hay alguna manera fácil de prevenir esto? De lo contrario, creo que podría volver al bit hide/show.

Respuesta

5

Podría depender de lo que intenta evitar que se vuelva a crear.

// Replace whatever is in the fragment_container view with this fragment, 
// and add the transaction to the back stack 
transaction.replace(R.id.fragment_container, newFragment); 
transaction.addToBackStack(null); 

En su ejemplo ejemplo, cuando se pulsa el botón de vuelta de su newFragment se mostrará el fragmento anterior (obtendrá un onCreateView, onActivityCreated pero sin onCreate) de manera que el fragmento no está siendo re-creado como tal. En cuanto a tu nuevoFragmento, puedes mantenerlo si planeas volver a utilizarlo, actualizando cualquier estado interno como se requiere en, por ejemplo, onCreate o onActivityCreated.

EDIT:

Si usted simplemente tiene una lista de menú con cada entrada invocando un fragmento diferente en un panel de la derecha a continuación, añadir a la pila de atrás no es lo que quiere. Para esto, puede salirse con la suya llamando al add(...) en cada fragmento por adelantado y simplemente ocultar/mostrar cada fragmento según sea necesario (no lo he probado). De lo contrario, sugeriría que se mantenga una referencia a cada fragmento, llame al replace(...) al seleccionar un elemento de menú diferente que garantice que no se agrega a la pila posterior.

+0

Quiero cambiar entre Fragmentos dependiendo de la selección del menú. Por lo tanto, quiero volver a mostrar el mismo Fragmento nuevamente si está seleccionando el mismo elemento del menú nuevamente. Con "replace" no pude encuentra el Fragmento a través de la etiqueta. – jellyfish

+1

Luego, simplemente me quedo con los fragmentos en la memoria y hago el reemplazo. No veo por qué tienes que encontrar el fragmento dado que puedes rastrear la selección del menú actual y saber qué fragmento es Sin embargo, cuando se selecciona un nuevo elemento de menú, no veo por qué no debería funcionar encontrar el fragmento por etiqueta (he hecho algo similar con un DialogFragment como lo hace, si la memoria sirve, el DialogFragment muestra en API población. – PJL

+0

Entonces, ¿estás sugiriendo que debería mantener un campo de referencia en mi clase para cada Fragmento? Para la otra parte, ve mi edición. – jellyfish

0

he encontrado una manera de utilizar la función de "etiqueta":

//... 
fragmentTransaction.add(R.id.framelayout_content, fragment1, "foo"); 
fragmentTransaction.add(R.id.framelayout_content, fragment2, "bar"); 

//... 

fragmentManager.findFragmentByTag("foo"); 
fragmentManager.findFragmentByTag("bar"); 

Sin embargo, esto parece funcionar un poco de forma asíncrona. Llamar al findFragmentByTag inmediatamente después de commit devolvería null. Solo más tarde, en mi caso en un evento OnOptionsItemSelected, se encontraron los fragmentos.También hay una función llamada findFragmentById(int), pero no es muy útil. El Id, si no se especifica en un diseño XML, es el mismo que el del contenedor, por lo que en este caso es R.id.framelayout_content. Si luego llama a la función con esta ID, solo puede acceder a uno de los Fragmentos adjuntos. (Supongo que es el último, pero no lo he comprobado. Parece ser siempre el mismo, sin embargo.)

yo no por un rápido vistazo a encontrar una manera de obtener el fragmento "activa" de mi FrameLayout, así que creo que voy a guardar la etiqueta del último Fragmento que se muestra en alguna parte.

+1

"Llamar a findFragmentByTag directamente después de que la confirmación devuelva nulo" puede ser causada por: > Calling commit() no realiza la transacción inmediatamente. Más bien, lo programa para ejecutarse en el hilo de la interfaz de usuario de la actividad (el hilo "principal") tan pronto como el hilo pueda hacerlo. " [Desarrolladores de Android] http://developer.android.com/guide/components/ fragments.html # Transactions) – PKeno

4

Para evitar la IllegalStateException

: Fragmento Ya se añadió

he encontrado una solución que se trabaja bien para mí: utilizar remove(AFrag) y add(BFrag) en su transacción, en lugar de replace().

Parece que es un error: 4th comment in the accepted answer.

+0

PJL ha mencionado algo similar en su comentario. Entonces, ¿eliminar/agregar mantiene vivo el Fragmento y se guarda su contenido? – jellyfish

+0

sí, mantengo una referencia a mAFrag y a mBFrag, después de la operación de quitar/agregar y popBackStack mAFrag mantiene su contenido. Además, si vuelvo a avanzar, mBFrag también conserva el contenido. Acabo de descubrir el comentario de @PJL, estaba oculto. Lo sentimos: S –

+0

pero remove() también elimina la vista principal del fragmento mientras replace() no lo hace –

1
fragmentTransactionOnClick.setTransition(FragmentTransaction.TRANSIT_EXIT_MASK); 

si agrega el. setTransition.exit transit_exit_mask las vistas anteriores no vendrán

Cuestiones relacionadas