¿Cómo puedo mantener el estado del fragmento cuando se agrega a la pila posterior?


160

He escrito una actividad ficticia que cambia entre dos fragmentos. Cuando pasas de FragmentA a FragmentB, FragmentA se agrega a la pila posterior. Sin embargo, cuando regreso a FragmentA (presionando hacia atrás), se crea un FragmentA totalmente nuevo y se pierde el estado en el que estaba. Tengo la sensación de que busco lo mismo que esta pregunta, pero he incluido un ejemplo de código completo para ayudar a solucionar el problema:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

Con algunos mensajes de registro agregados:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

Nunca llama a FragmentA.onSaveInstanceState y crea un nuevo FragmentA cuando devuelve el golpe. Sin embargo, si estoy en FragmentA y bloqueo la pantalla, se llama a FragmentA.onSaveInstanceState. Tan extraño ... ¿me equivoco al esperar que un fragmento agregado a la pila posterior no necesite recreación? Esto es lo que dicen los documentos :

Mientras que si llama a addToBackStack () cuando elimina un fragmento, el fragmento se detiene y se reanudará si el usuario navega hacia atrás.


3
@ Jan-Henk ¿Qué pasa con las cosas que hay que buscar? Por ejemplo, la posición de desplazamiento de a ListView. Parece demasiado salto de aro para adjuntar un escucha de desplazamiento y actualizar una variable de instancia.
Jake Wharton

2
@JakeWharton Estoy de acuerdo en que debería ser más fácil, pero que yo sepa, no hay forma de evitar esto porque se llama a onCreateView cuando se restaura un fragmento de la pila. Pero podría estar equivocado :)
Jan-Henk

1
onCreate no recibe llamadas. Entonces, ¿aparentemente está reutilizando la misma instancia pero llamando a onCreateView nuevamente? Cojo. Supongo que solo puedo almacenar en caché el resultado de onCreateView y simplemente devolver la vista existente si se vuelve a llamar a onCreateView.
Eric

1
Exactamente lo que estaba buscando durante horas. ¿Puede publicar cómo logró esto usando la variable de instancia?
Uma

1
Así que recientemente comencé mi propia implementación en github.com/frostymarvelous/Folio y encontré un problema. Puedo crear alrededor de 5 páginas / fragmentos complejos antes de comenzar a tener bloqueos OOM. Eso es lo que me llevó aquí. Ocultar y mostrar simplemente no es suficiente. Las vistas tienen demasiada memoria.
frostymarvelous

Respuestas:


120

Si regresa a un fragmento de la pila posterior, no vuelve a crear el fragmento, sino que reutiliza la misma instancia y comienza con onCreateView()el ciclo de vida del fragmento, consulte Fragmento del ciclo de vida .

Entonces, si desea almacenar el estado, debe usar variables de instancia y no confiar en él onSaveInstanceState().


32
La versión actual de la documentación contradice esta afirmación. El diagrama de flujo dice lo que usted dice, pero el texto en el área principal de la página dice onCreateView () solo se llama la primera vez que se muestra el Fragment: developer.android.com/guide/components/fragments.html Estoy luchando contra esto problema ahora, y no veo ningún método llamado al devolver un fragmento del backstack. (Android 4.2)
Colin M.

10
Intenté registrar su comportamiento. OnCreateView () siempre se llama cuando se muestra el fragmento.
princepiero

44
@ColinM. ¿Alguna solución para el problema?
tormenta de nieve

9
Esto no funciona para mi. ¡Las variables de mi instancia son nulas al volver al fragmento! ¿Cómo puedo salvar el estado?
Don Rhummy

55
Entonces, si no debemos transmitir en la instancia de guardado, ¿cómo debería guardar el estado y los datos del fragmento?
Mahdi

80

En comparación con Apple UINavigationControllery UIViewControllerGoogle, no funciona bien en la arquitectura de software de Android. Y el documento de Android sobre Fragmentno ayuda mucho.

Cuando ingresa FragmentB desde FragmentA, la instancia de FragmentA existente no se destruye. Cuando presiona Atrás en FragmentB y vuelve a FragmentA, no creamos una nueva instancia de FragmentA. Se onCreateView()llamará a la instancia de FragmentA existente .

La clave es que no debemos volver a inflar la vista en FragmentA onCreateView(), porque estamos usando la instancia de FragmentA existente. Necesitamos guardar y reutilizar rootView.

El siguiente código funciona bien. No solo mantiene el estado del fragmento, sino que también reduce la carga de RAM y CPU (porque solo inflamos el diseño si es necesario). No puedo creer que el código y el documento de muestra de Google nunca lo mencionen, sino que siempre inflan el diseño .

Versión 1 (No use la versión 1. Use la versión 2)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ Actualización el 3 de mayo de 2005: -------

Como se mencionó en los comentarios, a veces _rootView.getParent()es nulo onCreateView, lo que provoca el bloqueo. La versión 2 elimina _rootView en onDestroyView (), como sugirió dell116. Probado en Android 4.0.3, 4.4.4, 5.1.0.

Versión 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

¡¡¡ADVERTENCIA!!!

¡Esto es un HACK! Aunque lo estoy usando en mi aplicación, debes probar y leer los comentarios cuidadosamente.


38
Tener una referencia a la vista raíz del fragmento completo es una mala idea de la OMI. Si agrega continuamente varios fragmentos a un backstack y todos ellos mantienen su vista raíz (que tiene una huella de memoria bastante grande), entonces existe una gran posibilidad de que termine con OutOfMemoryError ya que todos los fragmentos contienen referencia de vista raíz y GC no puede recógelo. Creo que el mejor enfoque es inflar la vista todo el tiempo (y dejar que el sistema Android maneje su creación / destrucción de vista) y onActivityCreated / onViewCreated verifique si sus datos son nulos. En caso afirmativo, cárguelo, de lo contrario, configure los datos en vistas.
traninho

15
¡No hagas esto! Cuando se crea la jerarquía de vistas del Fragmento, contiene una referencia interna a la Actividad que contenía el fragmento en ese momento. Cuando se produce un cambio de configuración, la Actividad a menudo se vuelve a crear. Reutilizar el diseño anterior mantiene esa actividad zombie en la memoria junto con cualquier objeto al que también haga referencia. El desperdicio de memoria como este dificulta el rendimiento y hace que su aplicación sea la mejor candidata para la finalización inmediata cuando no está en primer plano.
Krylez

44
@AllDayAmazing Este es un buen punto. Para ser honesto, estoy muy confundido en este momento. ¿Alguien puede tratar de explicar por qué mantener una referencia a la vista raíz de un fragmento no está bien, pero mantener una referencia solo para cualquier hijo de rootview (que de todos modos tiene una referencia a la vista raíz) está bien?
traninho

2
MANTÉNGASE ALEJADO DE ESTO a menos que quiera perder 5 horas descubriendo lo que está averiando su código ..... luego solo para descubrir que esta es la causa. Ahora tengo que refactorizar un montón de cosas porque usé este truco. Es mucho mejor usar fragmentTransaction.add si desea mantener intacta la interfaz de usuario del fragmento al mostrar otro (incluso en la parte superior). fragmentTransaction.replace () está destinado a destruir las vistas del fragmento ... no luches contra el sistema.
dell116

2
@VinceYuan: probé con la última biblioteca v7-appcompat en Android 5.1 y esto dejó 6 instancias de un fragmento que debería haberse eliminado en el FragmentManager de mi actividad. Incluso si el GC lo manejará correctamente (lo cual no creo que lo haga), esto está causando una tensión innecesaria en la memoria de su aplicación y del dispositivo en general. Simplemente usando .add () elimina por completo la necesidad de todo este código hacky. Hacer esto está completamente en contra de lo que estaba destinado a usar FragmentTransaction.replace () en primer lugar.
dell116

53

Supongo que hay una forma alternativa de lograr lo que estás buscando. No digo que sea una solución completa, pero cumplió el propósito en mi caso.

Lo que hice es en lugar de reemplazar el fragmento que acabo de agregar el fragmento de destino. Así que básicamente vas a usar el add()método en su lugar replace().

¿Qué más hice? Oculto mi fragmento actual y también lo agrego al backstack.

Por lo tanto, se superpone a un nuevo fragmento sobre el fragmento actual sin destruir su vista (verifique que onDestroyView()no se llame a su método. Además, agregarlo backstateme da la ventaja de reanudar el fragmento).

Aquí está el código:

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

El sistema AFAIK solo llama onCreateView()si la vista se destruye o no se crea. Pero aquí hemos guardado la vista al no eliminarla de la memoria. Por lo tanto, no creará una nueva vista.

Y cuando regrese de Destination Fragment, aparecerá el último FragmentTransactionfragmento de eliminación que hará que la vista superior (SourceFragment) aparezca sobre la pantalla.

COMENTARIO: Como dije, no es una solución completa ya que no elimina la vista del fragmento de Fuente y, por lo tanto, ocupa más memoria de lo habitual. Pero aún así, cumple el propósito. Además, estamos utilizando un mecanismo totalmente diferente para ocultar la vista en lugar de reemplazarla, lo cual no es tradicional.

Por lo tanto, no se trata realmente de cómo mantiene el estado, sino de cómo mantiene la vista.


En mi caso, agregar un fragmento en lugar de reemplazarlo causa problemas cuando se utiliza el sondeo o se usa cualquier otro tipo de solicitud web en el fragmento. Quiero pausar este sondeo en el Fragmento A cuando se agrega el Fragmento B. ¿Alguna idea sobre esto?
Uma

¿Cómo está utilizando el sondeo en FirstFragment? Debe hacerlo manualmente, ya que ambos fragmentos permanecen en la memoria. Para que pueda usar sus instancias para realizar la acción necesaria. Esa es la pista, generar un evento en la actividad principal que haga algo cuando agregue el segundo fragmento. Espero que esto ayude.
kaushal trivedi

1
Gracias por la pista =). Tengo esto hecho. ¿Pero es esta la única forma de hacerlo? ¿Y una forma apropiada? Además, cuando presiono el botón de inicio y vuelvo a iniciar la aplicación, todos los fragmentos se activan nuevamente. Supongamos que estoy aquí en el Fragmento B de esta manera. Activity A{Fragment A --> Fragment B}cuando vuelvo a iniciar la aplicación después de presionar el botón de inicio, onResume()se llama a ambos fragmentos y, por lo tanto, comienzan su sondeo. ¿Cómo puedo controlar esto?
Uma

1
Desafortunadamente no puede, el sistema no funciona en el comportamiento normal de esta manera, considerará tanto el fragmento como hijo directo de la actividad. Aunque sirvió para mantener el estado del fragmento, otras cosas normales se vuelven muy difíciles de manejar. descubrí todos estos problemas, ahora mi sugerencia es no ir por este camino.
kaushal trivedi

1
Por supuesto, en el último diré que no siga este enfoque hasta que encuentre alguna otra solución, porque es difícil de administrar.
kaushal trivedi

7

Sugeriría una solución muy simple.

Tome la variable de referencia Ver y configure la vista en OnCreateView. Verifique si la vista ya existe en esta variable, luego devuelva la misma vista.

   private View fragmentView;

   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }

1
Existe la posibilidad de pérdida de memoria si no eliminamos la variable 'fragmentView' en onDestroy ()
Arun PM

@ArunPM entonces, ¿cómo eliminar fragmentView en onDestroy ()? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }Es apropiado borrar la memoria?
Mehmet Gür

1
@ MehmetGür Estoy usando esta solución muchas veces. Hasta ahora no recibí ningún error de pérdida de memoria. Pero puede usar la solución ArunPM con eso si lo desea. Creo que está diciendo que establezca fragmentView en nulo en el método OnDestroy ().
Mandeep Singh

1
Estoy usando LeakCanary para detectar fugas de memoria y sus problemas de fuga cuando seguí este método. Pero como @Mandeep Sigh mencionó en el comentario, podemos superar este problema asignando nulla la fragmentView variable en el onDestroy()método.
Arun PM

1
Según mi conocimiento, cuando un fragmento se destruye, la vista asociada con el fragmento se borra onDestroyView(). Este borrado no está ocurriendo para nuestra variable de vista de copia de seguridad (aquí fragmentView ) y provocará una pérdida de memoria cuando el fragmento vuelva a apilarse / destruirse. Puede encontrar la misma referencia en [Causas comunes de pérdidas de memoria] ( square.github.io/leakcanary/fundamentals/… ) en la introducción de LeakCanery.
Arun PM

6

Encontré este problema en un Fragmento que contiene un mapa, que tiene demasiados detalles de configuración para guardar / recargar. Mi solución fue básicamente mantener este Fragmento activo todo el tiempo (similar a lo que mencionó @kaushal).

Digamos que tiene el Fragmento A actual y quiere mostrar el Fragmento B. Resumiendo las consecuencias:

  • replace (): retire el Fragmento A y reemplácelo con el Fragmento B. El Fragmento A se volverá a crear una vez que se vuelva a colocar al frente
  • add () - (crea y) agrega un Fragmento B y se superpone al Fragmento A, que todavía está activo en segundo plano
  • remove (): se puede usar para eliminar el Fragmento B y volver a A. El Fragmento B se volverá a crear cuando se llame más adelante

Por lo tanto, si desea mantener ambos Fragmentos "guardados", solo alterne usando hide () / show ().

Pros : método fácil y simple para mantener múltiples fragmentos en ejecución
Contras : utiliza mucha más memoria para mantenerlos a todos en funcionamiento. Puede tener problemas, por ejemplo, mostrar muchos mapas de bits grandes


¿podría decirme cuándo eliminamos el fragmento b y volver a A, entonces qué método se llama en el Fragmento A? Quiero tomar alguna medida cuando eliminemos el fragmento B.
Google

5

onSaveInstanceState() solo se llama si hay un cambio de configuración.

Dado que cambia de un fragmento a otro, no hay cambio de configuración, por lo que no hay llamada a onSaveInstanceState()allí. ¿Qué estado no se salva? Se puede especificar?

Si ingresa algún texto en EditText, se guardará automáticamente. Cualquier elemento de la IU sin ningún ID es el elemento cuyo estado de vista no se guardará.


onSaveInstanceState()También se llama cuando el sistema destruye Actividad porque carece de recursos.
Marcel Bro

0

Aquí, ya que onSaveInstanceStateen fragment no se llama cuando agrega fragmento en backstack. El ciclo de vida del fragmento en el backstack cuando se restaura comienza onCreateViewy finaliza onDestroyViewmientras onSaveInstanceStatese llama entre onDestroyViewy onDestroy. Mi solución es crear variable de instancia e iniciar en onCreate. Código de muestra:

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

Y compruébalo en onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}

0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

0

Mi problema era similar pero me vencí sin mantener vivo el fragmento. Suponga que tiene una actividad que tiene 2 fragmentos: F1 y F2. F1 se inicia inicialmente y digamos que contiene información del usuario y luego, bajo alguna condición, F2 aparece al pedirle al usuario que complete el atributo adicional : su número de teléfono. Luego, desea que ese número de teléfono vuelva a F1 y complete el registro, pero se da cuenta de que toda la información del usuario anterior se pierde y no tiene sus datos anteriores. El fragmento se onSaveInstanceStatevuelve a crear desde cero e incluso si guardó esta información en el paquete vuelve a ser nulo onActivityCreated.

Solución: guarde la información requerida como una variable de instancia en la actividad de llamada. Luego pase esa variable de instancia en su fragmento.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

Entonces, siguiendo con mi ejemplo: antes de mostrar F2, guardo los datos del usuario en la variable de instancia utilizando una devolución de llamada. Luego comienzo F2, el usuario completa el número de teléfono y presiona guardar. Uso otra devolución de llamada en la actividad, recopilo esta información y reemplazo mi fragmento F1, esta vez tiene datos de paquete que puedo usar.

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

Puede encontrar más información sobre devoluciones de llamada aquí: https://developer.android.com/training/basics/fragments/communicating.html


0

primero : simplemente use el método add en lugar del método replace de la clase FragmentTransaction, luego debe agregar secondFragment para apilar mediante el método addToBackStack

segundo : al hacer clic de nuevo, debe llamar a popBackStackImmediate ()

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};

0

Reemplace un fragmento usando el siguiente código:

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

La actividad de onBackPressed () es:

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}

0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);

1
Gracias por este fragmento de código, que puede proporcionar una ayuda limitada e inmediata. Una explicación adecuada mejoraría en gran medida su valor a largo plazo al mostrar por qué esta es una buena solución al problema y lo haría más útil para futuros lectores con otras preguntas similares. Por favor, editar su respuesta a añadir un poco de explicación, incluyendo los supuestos realizados.
Machavity

0

Solución perfecta que encuentra un fragmento antiguo en la pila y lo carga si existe en la pila.

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

úsalo como

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.