La superposición de fragmentos ocultos después de la aplicación se muere y se restaura

Estoy cambiando entre fragmentos ocultando el último fragmento y añadiendo uno nuevo (ver código abajo) – añadiéndolo a la pila posterior también. De esta manera, los usuarios pueden cambiar rápidamente entre los fragmentos sin recargar los datos del fragmento.

Esto funciona bien hasta que se muera la aplicación (Escenario: los usuarios utilizan varias aplicaciones y mi aplicación se persiste y se mata).

Cuando un usuario abre la aplicación, se está restaurando y se muestran todos los fragmentos, superponiéndose entre sí.

Pregunta: ¿Cómo se pueden restaurar los fragmentos restaurados con su estado oculto? ¿Tal vez me falta alguna bandera? ¿algun lado? Tal vez hay una mejor solución para la conmutación rápida entre fragmentos (sin recargar los datos)?

Código de ejemplo de la adición de fragmentos – invocado varias veces con diferentes fragmentos al hacer clic en alguna parte:

FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.hide(lastFragment); fragmentTransaction.add(newFragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); lastFragment = newFragment; 

Espero que alguien encuentre una solución mejor. Voy a esperar uno antes de aceptar mi solución:

En general, utilizo etiquetas generadas para encontrar los fragmentos no ocultados y ocultarlos.

En detalles, generar una etiqueta única para cada fragmento (StackEntry) y apilar las etiquetas como los fragmentos se apilan. Persigo la pila en el bundel y la carga cuando la aplicación es restaurada con el fin de continure usarlo. Luego utilizo la lista de etiquetas para encontrar todos los fragmentos no ocultados y ocultarlos, excepto el último.

Heres ejemplo de código:

 public class FragmentActivity extends Activity { private static final String FRAGMENT_STACK_KEY = "FRAGMENT_STACK_KEY"; private Stack<StackEntry> fragmentsStack = new Stack<StackEntry>(); public FragmentActivity() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_frame); if (savedInstanceState == null) { // Init for the first time - not restore // ... } else { Serializable serializable = savedInstanceState.getSerializable(FRAGMENT_STACK_KEY); if (serializable != null) { // Workaround Android bug. // See: http://stackoverflow.com/questions/13982192/when-using-an-android-bundle-why-does-a-serialised-stack-deserialise-as-an-arra // And: https://code.google.com/p/android/issues/detail?id=3847 @SuppressWarnings("unchecked") List<StackEntry> arrayList = (List<StackEntry>) serializable; fragmentsStack = new Stack<StackEntry>(); fragmentsStack.addAll(arrayList); } // Hide all the restored fragments instead of the last one if (fragmentsStack.size() > 1) { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); for (int i = 0; i < fragmentsStack.size()-1; i++) { String fragTag = fragmentsStack.get(i).getFragTag(); Fragment fragment = getFragmentManager().findFragmentByTag(fragTag); fragmentTransaction.hide(fragment); } fragmentTransaction.commit(); } } getFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() { @Override public void onBackStackChanged() { Fragment lastFragment = getLastFragment(); if (lastFragment.isHidden()) { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.show(lastFragment); fragmentTransaction.commit(); } } }); } private Fragment getLastFragment() { if (fragmentsStack.isEmpty()) return null; String fragTag = fragmentsStack.peek().getFragTag(); Fragment fragment = getFragmentManager().findFragmentByTag(fragTag); return fragment; } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable(FRAGMENT_STACK_KEY, fragmentsStack); } @Override public void onBackPressed() { if (!fragmentsStack.isEmpty()) { fragmentsStack.pop(); } } public void switchContent(Fragment fragment) { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); Fragment lastFragment = getLastFragment(); if (lastFragment != null) { fragmentTransaction.hide(lastFragment); } String fragTag; if (fragment.isAdded()) { fragmentTransaction.show(fragment); fragTag = fragment.getTag(); } else { fragTag = Long.toString(System.currentTimeMillis()); fragmentTransaction.add(R.id.content_frame, fragment, fragTag); } if (!isFirstFragment()) { // Add to backstack only the first content fragment and not the state before (that has nothing) fragmentTransaction.addToBackStack(null); } fragmentTransaction.commit(); fragmentsStack.push(new StackEntry(fragTag)); } public boolean isFirstFragment() { return fragmentsStack.size() == 0; } private static class StackEntry implements Serializable { private static final long serialVersionUID = -6162805540320628024L; private String fragTag = null; public StackEntry(String fragTag) { super(); this.fragTag = fragTag; } public String getFragTag() { return fragTag; } } public static class Intent extends android.content.Intent { public Intent(Context packageContext) { super(packageContext, FragmentActivity.class); } } } 

También tuve este problema, he aquí una posible solución: que cada fragmento guarde su propio estado sobre si estaba o no escondido, y luego se esconde en su onCreate.

 @Override public void onSaveInstanceState(Bundle bundle) { super.onSaveInstanceState(bundle); if (this.isHidden()) { bundle.putBoolean("hidden", true); } } @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); if (bundle != null) { if (bundle.getBoolean("hidden", false)) { getFragmentManager() .beginTransaction() .hide(this) .commit(); } } } 

Finalmente encontré la forma más sencilla de arreglar este problema: Cambiar frame_de_control de FramLayout a LinearLayout.

Tuve el mismo problema, y ​​lo resolví estableciendo setRetainInstance(true); En el método onCreate() de cada fragmento.

Tuve el mismo problema. Desafortunadamente la única buena solución fue cambiar a usar fragmentTransaction.replace lugar de fragmentTransaction.hide y agregar.

Me chupó en el momento, pero estoy realmente contento de haberlo hecho. Me obligó a pensar en savedInstanceState y tratar con él correctamente. Usted mencionó que al navegar hacia atrás el fragmento es recargado. Tuve exactamente el mismo problema que me obligó a manejar savedInstanceState correctamente. Hay 2 casos allí.

  1. Si la actividad no se destruyó la única cosa que necesitaba recrear era la vista (vía onCreateView ) todo lo demás está todavía en la memoria por lo que era sólo una cuestión de enganchar el adaptador hasta la vista y ya está.

  2. Si la actividad fue destruida necesité recrear la vista y el adaptador. Para minimizar el tiempo de carga savedInstanceState los datos necesarios para recrear el adaptador en savedInstanceState

Su queja es sin embargo válida, no sé por qué Android no apoya volver con el estado oculto correcto de una actividad destruida con los fragmentos que utilizaban agrega y ocultar.

Puesto que mencionaste que no te importa tener los fragmentos recargados desde cero, ¿por qué no usar la intención y comenzar de nuevo la actividad del fragmento principal de nuevo?

Me enfrenté a la misma cuestión como la que usted ha mencionado, donde los fragmentos se superponían unos con otros. Miré por todas partes stackoverflow y encontré sólo este hilo donde se discutió este problema en particular. He intentado la solución proporcionada por Walt , pero no funcionó como se esperaba.

La siguiente solución funciona al menos para mí, por lo que compartirlo en caso de que alguien termina con este escenario

En onSaveInstanceState en el fragmento padre, establezco un marcador para asegurarse de que hay algo guardado en el paquete.

 public void onSaveInstanceState(Bundle outState) { // TODO Auto-generated method stub super.onSaveInstanceState(outState); outState.putString(TAG, "Get ready to be terminated"); }; 

Y dentro onCreate puedes especificar tu clase para cargar usando Intent cuando el estado de la instancia guardada no es nulo,

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.layout); if(savedInstanceState != null) { Intent myIntent = new Intent(this, your.class); // Closing the parent fragment finish(); this.startActivity(myIntent); } else { // your main code ........... ........... }; }; 

Esto asegurará que sus fragmentos se recreen desde cero.

En mi caso, cuando un usuario abrió mi aplicación, tenía una pantalla de inicio de sesión y si ya estaban "conectados" antes de que sean redirigidos a las pantallas de fragmentos.

Durante el proceso de eliminación, vuelvo a dirigir a los usuarios a la página de inicio de sesión una vez que la aplicación llega al primer plano ya partir de ahí mi código ya existente se encarga de volver a dirigir al usuario de nuevo a las pantallas de fragmentos recién creadas.

Nota: Debe asegurarse de que el fragmento de su hijo no tenga cabos sueltos en onCreateView .

Me encontré con el mismo problema, creo que este es Android framework bug.Here es el problema .

Sin embargo mi manera trabajará para usted, debemos onSaveInstanceState(Bundle outState) el onSaveInstanceState(Bundle outState) método, excepto nuestros datos de encargo al outState , pero nunca llamar a super.onSaveInstanceState(outState); .

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ...... if (savedInstanceState != null) { mCustomVariable = savedInstanceState.getInt("variable", 0); } } @Override protected void onSaveInstanceState(Bundle outState) { //super.onSaveInstanceState(outState); outState.putInt("variable", mCustomVariable); } 
  • Manejar la tecla de retroceso cuando el último fragmento se disparó
  • Android - ImageLoader debe ser init con la configuración antes de usar en UIL
  • Pasar los datos de los elementos de los clics hechos por RecyclerView CardView a la actividad
  • ArrayAdapter en Fragmento - Android
  • MapActivity en TabHost Fragmento que desaparece después de cambiar la pestaña
  • ¿Cómo puedo abrir un nuevo fragmento de otro fragmento
  • Loader no se inicia después de llamar a initLoader ()?
  • ¿Por qué mi inicio de sesión de facebook android sdk se llama dos veces?
  • Android - ListFragment dentro DialogFragment (AlertDialog): Fragmento no tiene una vista
  • Refrescar la visualización de datos en un fragmento
  • Android - ¿Por qué debería implementar la interfaz mientras se comunica entre la actividad principal y el fragmento
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.